Outpost Admin API Reference
The Outpost Admin API is a separate FastAPI application that listens on port 8301 (local-only). It provides emergency override capabilities, local status inspection, and operational controls without requiring connectivity to the Arbitex platform.
Air-gap compatible. All admin API calls are local. No data is forwarded to the platform during admin operations.
Authentication
Section titled “Authentication”All endpoints require a Bearer token in the Authorization header:
Authorization: Bearer <admin-api-key>Token resolution order:
admin_users[].api_keyfrom the loaded policy bundle (HMAC compare — constant time)OUTPOST_EMERGENCY_ADMIN_KEYenvironment variable as a fallback- A valid HS256/EdDSA JWT obtained from
POST /admin/api/auth/login
Brute-force protection: 5 failed authentication attempts per IP within a 15-minute sliding window triggers HTTP 429. The window resets automatically.
CORS: The admin API only accepts requests from http://localhost:8301 and http://127.0.0.1:8301. All other origins are rejected.
Replay protection: When REPLAY_PROTECTION_ENABLED=true, state-changing endpoints (POST/PUT/DELETE) require an X-Request-ID header. Duplicate X-Request-ID values return 409 Conflict.
Master Endpoint Summary
Section titled “Master Endpoint Summary”| Method | Path | Section |
|---|---|---|
POST |
/admin/api/auth/login |
Authentication & Authorization |
POST |
/admin/api/auth/refresh |
Authentication & Authorization |
POST |
/admin/api/auth/revoke |
Authentication & Authorization |
GET |
/admin/api/auth/revocation-list |
Authentication & Authorization |
POST |
/admin/api/auth/revocation-list/clear |
Authentication & Authorization |
GET |
/admin/api/sessions |
Authentication & Authorization |
DELETE |
/admin/api/sessions/{session_id} |
Authentication & Authorization |
GET |
/admin/api/auth-events |
Authentication & Authorization |
GET |
/admin/api/status |
Status & Health |
GET |
/admin/api/sync-status |
Status & Health |
GET |
/admin/api/airgap-config |
Status & Health |
GET |
/admin/api/health |
Status & Health |
GET |
/admin/api/health/summary |
Status & Health |
GET |
/admin/api/health/components |
Status & Health |
GET |
/admin/api/health/cluster |
Status & Health |
GET |
/admin/api/connection-health |
Status & Health |
GET |
/admin/api/connection-health/history |
Status & Health |
GET |
/admin/api/compat |
Status & Health |
GET |
/admin/api/rules |
Policy & DLP |
POST |
/admin/api/rules/{rule_id}/toggle |
Policy & DLP |
GET |
/admin/api/rulesets |
Policy & DLP |
POST |
/admin/api/rulesets/{ruleset_id}/toggle |
Policy & DLP |
POST |
/admin/api/policy/simulate |
Policy & DLP |
GET |
/admin/api/policy/verify |
Policy & DLP |
POST |
/admin/api/policy/reload |
Policy & DLP |
GET |
/admin/api/custom-patterns |
Policy & DLP |
POST |
/admin/api/custom-patterns |
Policy & DLP |
DELETE |
/admin/api/custom-patterns/{name} |
Policy & DLP |
GET |
/admin/api/providers |
Provider Management |
POST |
/admin/api/providers/{provider}/disable |
Provider Management |
POST |
/admin/api/providers/{provider}/enable |
Provider Management |
GET |
/admin/api/credint/status |
Credential Intelligence |
POST |
/admin/api/credint/reload |
Credential Intelligence |
POST |
/admin/api/credint/kanon |
Credential Intelligence |
GET |
/admin/api/usage |
Budget & Usage |
GET |
/admin/api/budget/status |
Budget & Usage |
GET |
/admin/api/budget/export.csv |
Budget & Usage |
GET |
/admin/api/cert/status |
Certificate Management |
POST |
/admin/api/cert/renew |
Certificate Management |
GET |
/admin/api/certs/status |
Certificate Management |
POST |
/admin/api/certs/rotate |
Certificate Management |
GET |
/admin/api/audit-buffer |
Audit & SIEM |
GET |
/admin/audit/recent |
Audit & SIEM |
GET |
/admin/audit/stats |
Audit & SIEM |
GET |
/admin/audit/search |
Audit & SIEM |
GET |
/admin/audit/verify |
Audit & SIEM |
GET |
/admin/api/audit/verify |
Audit & SIEM |
GET |
/admin/api/audit-sync/checkpoint |
Audit & SIEM |
GET |
/admin/api/siem/status |
Audit & SIEM |
GET |
/admin/audit-queue/status |
Audit & SIEM |
POST |
/admin/audit-queue/flush |
Audit & SIEM |
DELETE |
/admin/audit-queue/purge |
Audit & SIEM |
GET |
/admin/api/config/export |
Configuration |
GET |
/admin/config/export |
Configuration |
POST |
/admin/api/config/backup |
Configuration |
GET |
/admin/api/config/backup/list |
Configuration |
POST |
/admin/api/config/restore |
Configuration |
POST |
/admin/config/diff |
Configuration |
GET |
/admin/config/validate |
Configuration |
GET |
/admin/api/config/reload-status |
Configuration |
POST |
/admin/api/config/reload |
Configuration |
POST |
/admin/api/config/apply |
Configuration |
GET |
/admin/api/config/reload-history |
Configuration |
GET |
/admin/api/orgs |
Multi-Org |
GET |
/admin/api/orgs/{org_id}/policy-status |
Multi-Org |
GET |
/admin/api/cache/stats |
Multi-Org |
POST |
/admin/api/cache/clear |
Multi-Org |
POST |
/admin/api/emergency-kill |
Kill Switch & Drain |
GET |
/admin/api/drain/status |
Kill Switch & Drain |
GET |
/admin/api/prompt-holds |
Kill Switch & Drain |
POST |
/admin/api/prompt-holds/{hold_id}/approve |
Kill Switch & Drain |
POST |
/admin/api/prompt-holds/{hold_id}/deny |
Kill Switch & Drain |
GET |
/admin/api/prompt-holds/events |
Kill Switch & Drain |
POST |
/admin/api/prompt-holds/bulk-approve |
Kill Switch & Drain |
POST |
/admin/api/routing-override |
Kill Switch & Drain |
GET |
/admin/api/plugins |
Plugins & Webhooks |
POST |
/admin/api/plugins/{name}/enable |
Plugins & Webhooks |
POST |
/admin/api/plugins/{name}/disable |
Plugins & Webhooks |
GET |
/admin/api/webhook-emitter/stats |
Plugins & Webhooks |
GET |
/admin/api/updates/status |
Software Updates |
POST |
/admin/api/updates/check |
Software Updates |
POST |
/admin/api/updates/download |
Software Updates |
GET |
/admin/api/upgrade/status |
Software Updates |
POST |
/admin/api/upgrade/run |
Software Updates |
POST |
/admin/api/upgrade/rollback |
Software Updates |
GET |
/admin/api/upgrade/history |
Software Updates |
GET |
/admin/diagnostics |
Operational Tools |
GET |
/admin/api/metrics-summary |
Operational Tools |
GET |
/admin/api/metrics/connections |
Operational Tools |
GET |
/admin/api/circuit-breakers |
Operational Tools |
GET |
/admin/api/bandwidth |
Operational Tools |
GET |
/admin/api/benchmarks |
Operational Tools |
GET |
/admin/api/log-export/status |
Operational Tools |
GET |
/admin/api/otel/status |
Operational Tools |
GET |
/admin/api/pushgateway/status |
Operational Tools |
GET |
/admin/api/ip-allowlist/status |
Operational Tools |
GET |
/admin/api/body-hash/config |
Operational Tools |
GET |
/admin/api/replay-protection/stats |
Operational Tools |
1. Authentication & Authorization
Section titled “1. Authentication & Authorization”This section covers JWT-based authentication, session management, and authentication event retrieval. Static Bearer token auth is described in the Authentication section above.
POST /admin/api/auth/login
Section titled “POST /admin/api/auth/login”Issue a signed JWT for admin API access.
POST /admin/api/auth/loginContent-Type: application/jsonRequest body
{"api_key": "your-admin-api-key"}Response 200 OK
{ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...", "expires_at": "2026-03-16T12:00:00Z"}Use the returned token in the Authorization: Bearer <token> header for subsequent requests.
POST /admin/api/auth/refresh
Section titled “POST /admin/api/auth/refresh”Refresh a JWT that is within 5 minutes of expiry. Pass the current (non-expired) token as the Authorization header.
curl -s -X POST "http://localhost:8301/admin/api/auth/refresh" \ -H "Authorization: Bearer $CURRENT_JWT"Response 200 OK
{ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...", "expires_at": "2026-03-16T13:00:00Z"}Returns 400 Bad Request if the token is not within 5 minutes of expiry. Returns 401 Unauthorized if the token is already expired.
POST /admin/api/auth/revoke
Section titled “POST /admin/api/auth/revoke”Revoke a JWT by adding its JTI (JWT ID) to the in-memory revocation list. The revoked token is rejected on all subsequent requests until the revocation list is cleared or the outpost restarts.
curl -s -X POST "http://localhost:8301/admin/api/auth/revoke" \ -H "Authorization: Bearer $JWT_TO_REVOKE"Response 200 OK
GET /admin/api/auth/revocation-list
Section titled “GET /admin/api/auth/revocation-list”Return the count of revoked JTIs and the timestamp of the last list clear.
Response 200 OK
{ "revoked_count": 3, "last_cleared": "2026-03-15T08:00:00Z"}POST /admin/api/auth/revocation-list/clear
Section titled “POST /admin/api/auth/revocation-list/clear”Clear the entire revocation list. All previously revoked tokens become valid again.
Response 200 OK
GET /admin/api/sessions
Section titled “GET /admin/api/sessions”List all currently active admin sessions. Expired sessions are cleaned up before the response is returned.
curl -s http://outpost.internal:8301/admin/api/sessions \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "sessions": [ { "id": "sess_7a3b9f1c2e4d5a6b", "username": "ops-admin", "ip": "10.0.1.42", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36", "created_at": "2026-03-15T11:00:00Z", "last_activity": "2026-03-15T11:28:45Z" } ], "count": 1}| Field | Type | Description |
|---|---|---|
id |
string | Session identifier |
username |
string | Admin username associated with the session |
ip |
string | Source IP address |
user_agent |
string | HTTP User-Agent string from the login request |
created_at |
datetime | Session creation timestamp |
last_activity |
datetime | Most recent request timestamp |
DELETE /admin/api/sessions/{session_id}
Section titled “DELETE /admin/api/sessions/{session_id}”Force-logout an active admin session by ID. Writes an auth.session.revoked audit event.
Path parameters
| Parameter | Type | Description |
|---|---|---|
session_id |
string | Session ID from GET /admin/api/sessions |
curl -s -X DELETE \ http://outpost.internal:8301/admin/api/sessions/sess_a1b2c3d4 \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "revoked": "sess_7a3b9f1c2e4d5a6b", "username": "ops-admin"}Returns 404 Not Found if the session is not found or already expired.
GET /admin/api/auth-events
Section titled “GET /admin/api/auth-events”Return the most recent authentication events (auth.*) from the local audit queue. Limited to the last 100 entries.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
int | 20 | Maximum events to return (capped at 100) |
Response 200 OK
{ "events": [ { "event": "auth.login.success", "username": "ops-alice", "ip": "10.0.1.42", "timestamp": "2026-03-16T14:07:33Z" }, { "event": "auth.session.revoked", "revoked_session_id": "sess_old123", "revoked_by": "ops-alice", "timestamp": "2026-03-16T14:05:00Z" } ], "count": 2}Returns {"events": [], "count": 0} if the audit queue is not initialized.
2. Status & Health
Section titled “2. Status & Health”These endpoints provide operational visibility into the outpost state, health checks at varying granularity levels, and real-time connection metrics.
GET /admin/api/status
Section titled “GET /admin/api/status”Returns the current outpost operational status: policy version, active override count, uptime, and emergency kill state.
GET /admin/api/statusAuthorization: Bearer <token>Response 200 OK
{ "outpost_id": "prod-outpost-01", "policy_version": "v2026.03.12-4", "uptime_seconds": 86400, "active_override_count": 2, "emergency_kill": false, "last_override_modified": "2026-03-12T08:00:00Z", "routing_override": null, "update_available": true, "latest_version": "0.19.2"}| Field | Description |
|---|---|
active_override_count |
Sum of all active provider, rule, ruleset, and routing overrides + kill switch |
emergency_kill |
true if the emergency kill switch is active (all requests blocked) |
routing_override |
Provider name if routing is pinned; null if using policy-default routing |
update_available |
true if latest_version differs from the running outpost version |
GET /admin/api/sync-status
Section titled “GET /admin/api/sync-status”Returns policy sync health: last sync timestamp, ETag, bundle version, heartbeat status, and TLS certificate expiry.
GET /admin/api/sync-statusAuthorization: Bearer <token>Response 200 OK
{ "last_sync_at": "2026-03-12T08:52:00Z", "etag": "\"abc123\"", "bundle_version": "v2026.03.12-4", "latest_version": "0.19.2", "heartbeat": { "last_sent_at": "2026-03-12T08:55:00Z", "consecutive_failures": 0 }, "cert_expiry_days": 82.5}cert_expiry_days is null if no certificate path is configured. A value below 30 should trigger a certificate renewal.
GET /admin/api/airgap-config
Section titled “GET /admin/api/airgap-config”Returns the read-only air-gap configuration from OutpostSettings. Useful for verifying that air-gap mode is configured correctly.
GET /admin/api/airgap-configAuthorization: Bearer <token>Response 200 OK
{ "airgap_enabled": true, "policy_path": "/etc/arbitex/policy.json", "model_path": "/etc/arbitex/models/", "siem_output": "file:///var/log/arbitex/siem.jsonl", "hmac_enabled": true, "outpost_id": "prod-outpost-01"}hmac_enabled is false only when OUTPOST_INSECURE_SKIP_HMAC=true is set (development only).
GET /admin/api/health
Section titled “GET /admin/api/health”Config validation health check — runs all startup validation checks and reports pass/fail/warn/skip per check. Includes degradation mode status and TLS configuration summary.
curl -s http://outpost.internal:8301/admin/api/health \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "overall": "pass", "passed": 14, "failed": 0, "warned": 1, "skipped": 2, "checks": [ { "name": "admin_api_key", "status": "pass", "message": "ADMIN_API_KEY is set" }, { "name": "tls_cert", "status": "warn", "message": "Certificate expires in 28 days" } ], "degradation_mode": false, "degraded_since": null, "tls_config": { "min_version": "1.2", "max_version": "1.3", "verify_client": true }}overall is "fail" if any check fails, "warn" if any check warns, otherwise "pass".
GET /admin/api/health/summary
Section titled “GET /admin/api/health/summary”Condensed health response for fleet monitoring tools and dashboards.
curl -s http://outpost.internal:8301/admin/api/health/summary \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "status": "healthy", "uptime_seconds": 86412.3, "version": "0.14.2", "mode": "single", "active_orgs": 0, "inflight_requests": 3, "cache_hit_rate": 94.7, "circuit_breaker_open": false}| Field | Description |
|---|---|
status |
healthy / degraded / unhealthy — aggregate of proxy, DLP, and policy sync health |
mode |
single (single-org) or multi (multi-org mode) |
active_orgs |
Count of active orgs (multi-org mode only; 0 in single-org mode) |
inflight_requests |
Current in-flight DLP scan count |
cache_hit_rate |
Policy cache hit rate percentage |
GET /admin/api/health/components
Section titled “GET /admin/api/health/components”Component-level health breakdown with latency and detail fields. Suitable for dashboards and alerting.
curl -s http://outpost.internal:8301/admin/api/health/components \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK (or 503 Service Unavailable when overall is unhealthy)
{ "status": "healthy", "components": { "platform_connection": { "status": "healthy", "latency_ms": 42.3, "last_check": "2026-03-16T14:07:10Z" }, "model_service": { "status": "healthy", "last_check": "2026-03-16T14:07:15Z", "dlp_enabled": true, "ner_enabled": false }, "cert": { "status": "healthy", "days_remaining": 89 }, "config": { "status": "healthy", "reload_count": 3 } }}Component statuses: healthy / degraded / unhealthy. Platform connection is degraded when last sync is > 5 minutes old and unhealthy when > 1 hour old or the circuit breaker is open.
GET /admin/api/health/cluster
Section titled “GET /admin/api/health/cluster”Aggregate health status across all outpost peers in the cluster. Queries peers configured via CLUSTER_PEERS. Returns 207 when any peer is degraded, 503 when any peer is unhealthy.
curl -s http://outpost.internal:8301/admin/api/health/cluster \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK (all healthy)
{ "status": "healthy", "peers": [ {"url": "self (outpost-prod-01)", "status": "healthy"}, {"url": "http://outpost-prod-02:8301", "status": "healthy"} ], "total": 2, "healthy": 2, "degraded": 0, "unhealthy": 0}| HTTP Status | Meaning |
|---|---|
200 |
All peers healthy |
207 |
At least one peer degraded |
503 |
At least one peer unhealthy or unreachable |
GET /admin/api/connection-health
Section titled “GET /admin/api/connection-health”Real-time connection health metrics from the connection health monitor: latency percentiles, packet loss, and jitter.
curl -s http://outpost.internal:8301/admin/api/connection-health \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "status": "healthy", "enabled": true, "total_probes": 1440, "avg_latency_ms": 18.4, "p95_latency_ms": 42.1, "p99_latency_ms": 87.3, "packet_loss_pct": 0.0, "jitter_ms": 3.2, "probe_count": 60, "success_count": 60}Returns {"status": "unknown", "enabled": false, ...} when the connection health monitor is not configured.
GET /admin/api/connection-health/history
Section titled “GET /admin/api/connection-health/history”Return the raw probe history for the connection health monitor. Each entry represents one probe cycle against each AI provider.
curl -s "http://localhost:8301/admin/api/connection-health/history" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY"Response 200 OK
[ { "probed_at": "2026-03-16T09:00:00Z", "results": [ {"provider": "openai", "latency_ms": 142, "status": "ok"}, {"provider": "anthropic", "latency_ms": 198, "status": "ok"} ] }, { "probed_at": "2026-03-16T08:55:00Z", "results": [ {"provider": "openai", "latency_ms": 3001, "status": "timeout"}, {"provider": "anthropic", "latency_ms": 201, "status": "ok"} ] }]GET /admin/api/compat
Section titled “GET /admin/api/compat”Run version compatibility checks across all outpost components and return a structured matrix summary.
curl -s http://outpost.internal:8301/admin/api/compat \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "overall": "pass", "components": [ { "name": "platform_api", "detected_version": "1.14.0", "min_version": "1.12.0", "recommended_version": "1.14.0", "status": "pass", "message": "Platform API version compatible" }, { "name": "outpost_agent", "detected_version": "0.14.2", "min_version": "0.12.0", "recommended_version": "0.14.x", "status": "pass", "message": "Outpost version compatible" } ]}Check statuses: pass / warn / fail / skip.
3. Policy & DLP
Section titled “3. Policy & DLP”These endpoints manage DLP rules, rulesets, custom redaction patterns, policy simulation, policy verification, and air-gap policy reload.
GET /admin/api/rules
Section titled “GET /admin/api/rules”Lists all DLP rules from the loaded policy bundle with their enabled/disabled state.
GET /admin/api/rulesAuthorization: Bearer <token>Response 200 OK
{ "rules": [ { "id": "pii-ssn", "name": "SSN Detection", "tier": 1, "action": "block", "enabled": true }, { "id": "pii-ccn", "name": "Credit Card Number", "tier": 1, "action": "redact", "enabled": false } ]}POST /admin/api/rules/{rule_id}/toggle
Section titled “POST /admin/api/rules/{rule_id}/toggle”Enables or disables a specific DLP rule. The change takes effect immediately for all subsequent requests.
POST /admin/api/rules/{rule_id}/toggleAuthorization: Bearer <token>Content-Type: application/json
{ "enabled": false}Response 200 OK
{ "rule_id": "pii-ccn", "enabled": false}GET /admin/api/rulesets
Section titled “GET /admin/api/rulesets”Lists all DLP compliance rulesets (compliance_bundles in the policy bundle) with their enabled/disabled state.
GET /admin/api/rulesetsAuthorization: Bearer <token>Response 200 OK
{ "rulesets": [ { "id": "hipaa", "name": "HIPAA PHI", "enabled": true }, { "id": "pci-dss", "name": "PCI DSS", "enabled": false } ]}POST /admin/api/rulesets/{ruleset_id}/toggle
Section titled “POST /admin/api/rulesets/{ruleset_id}/toggle”Enables or disables an entire compliance ruleset. Disabling a ruleset suppresses all rules within it.
POST /admin/api/rulesets/{ruleset_id}/toggleAuthorization: Bearer <token>Content-Type: application/json
{ "enabled": false}Response 200 OK
{ "ruleset_id": "pci-dss", "enabled": false}POST /admin/api/policy/simulate
Section titled “POST /admin/api/policy/simulate”Runs a synthetic prompt through the local DLP pipeline and returns a full evaluation trace. Read-only — no request is forwarded to any LLM, no usage is recorded, and the prompt text is not written to the audit log (only its length is logged).
POST /admin/api/policy/simulateAuthorization: Bearer <token>Content-Type: application/json
{ "prompt": "My SSN is 123-45-6789, please help me...", "provider": "anthropic", "model": "claude-sonnet-4-6", "org_id": "b3e2a1c0-..."}| Field | Required | Description |
|---|---|---|
prompt |
Yes | Text to evaluate |
provider |
No | Provider to use for rule-provider matching |
model |
No | Model ID for model-specific rules |
org_id |
No | Defaults to the outpost’s configured org_id |
Returns 503 if no policy bundle is loaded.
Response — see Policy Simulator guide for full response schema.
GET /admin/api/policy/verify
Section titled “GET /admin/api/policy/verify”Return the last policy rule verification result from the most recent successful policy sync. Populated automatically after each HMAC-verified policy sync. Returns 404 if no bundle has been synced and verified in the current session.
Response 200 OK
{ "bundle_version": "v2026.03.16-1", "verified_at": "2026-03-16T14:00:00Z", "rules_count": 47, "packs_count": 8, "hmac_valid": true, "schema_version": "3", "warnings": []}Response 404 Not Found (no bundle synced yet)
{"detail": "No policy verification result available yet"}POST /admin/api/policy/reload
Section titled “POST /admin/api/policy/reload”Reload the policy bundle from the local filesystem. Only available when OUTPOST_AIRGAP=true. Reads policy_bundle.json from AIRGAP_POLICY_PATH, validates structure, and atomically replaces the active bundle in memory.
curl -s -X POST http://outpost.internal:8301/admin/api/policy/reload \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "success": true, "bundle_version": "2026-03-16T12:00:00Z", "rules_loaded": 47, "message": "Policy bundle reloaded from /opt/arbitex/policy/policy_bundle.json"}Response 400 Bad Request
{ "detail": "Policy reload only available in air-gap mode"}Response 422 Unprocessable Entity — bundle validation failed
{ "success": false, "bundle_version": null, "rules_loaded": 0, "message": "Policy bundle must contain a 'rules' array"}GET /admin/api/custom-patterns
Section titled “GET /admin/api/custom-patterns”List all loaded custom redaction patterns. Custom patterns extend the built-in DLP regex tier with operator-defined patterns. Enabled via CUSTOM_PATTERNS_ENABLED=true.
Response 200 OK
{ "patterns": [ { "name": "employee-id", "pattern": "EMP-[0-9]{6}", "replacement": "[EMPLOYEE_ID]", "enabled": true } ]}Returns {"patterns": []} if the custom pattern registry is not enabled.
POST /admin/api/custom-patterns
Section titled “POST /admin/api/custom-patterns”Add a new custom redaction pattern.
Request body
{ "name": "employee-id", "pattern": "EMP-[0-9]{6}", "replacement": "[EMPLOYEE_ID]", "enabled": true}| Field | Type | Required | Default |
|---|---|---|---|
name |
string | yes | — |
pattern |
string | yes | — |
replacement |
string | no | "[REDACTED]" |
enabled |
boolean | no | true |
Response 201 Created
{ "status": "added", "pattern": { "name": "employee-id", "pattern": "EMP-[0-9]{6}", "replacement": "[EMPLOYEE_ID]", "enabled": true }}Response 400 Bad Request: Missing name or pattern, or invalid regex.
Response 503 Service Unavailable: Custom pattern registry not enabled.
DELETE /admin/api/custom-patterns/{name}
Section titled “DELETE /admin/api/custom-patterns/{name}”Delete a custom redaction pattern by name.
Path parameter: name — the exact pattern name as registered.
Response 200 OK
{ "status": "deleted", "name": "employee-id"}Response 404 Not Found: Pattern not found.
4. Provider Management
Section titled “4. Provider Management”Providers can be temporarily disabled for maintenance, incident response, or cost control without modifying the policy bundle. All provider overrides are in-memory and reset on outpost restart.
GET /admin/api/providers
Section titled “GET /admin/api/providers”Lists all providers from the loaded policy bundle along with their current override state.
GET /admin/api/providersAuthorization: Bearer <token>Response 200 OK
{ "providers": [ { "name": "anthropic", "base_url": "https://api.anthropic.com", "models": ["claude-sonnet-4-6", "claude-haiku-4-5-20251001"], "disabled": false, "disabled_until": null, "disable_reason": "" }, { "name": "openai", "base_url": "https://api.openai.com", "models": ["gpt-4o", "gpt-4o-mini"], "disabled": true, "disabled_until": "2026-03-12T12:00:00Z", "disable_reason": "Incident response — elevated error rate", "override": { "disabled_by": "admin", "disabled_at": "2026-03-16T08:30:00Z", "disabled_until": "2026-03-16T10:30:00Z", "reason": "Maintenance window" } } ]}disabled_until is null for a permanent disable (no duration specified).
POST /admin/api/providers/{provider}/disable
Section titled “POST /admin/api/providers/{provider}/disable”Disables a provider, optionally for a fixed duration. All requests routed to this provider will fail with 503 until re-enabled.
POST /admin/api/providers/{provider}/disableAuthorization: Bearer <token>Content-Type: application/json
{ "duration_hours": 4, "reason": "Incident response — elevated error rate"}| Field | Type | Required | Description |
|---|---|---|---|
duration_hours |
float | No | Auto-re-enable after this many hours. Omit for permanent disable |
duration_minutes |
integer | No | Alternative to duration_hours |
reason |
string | No | Reason recorded in the audit log |
Returns 400 if the provider name is not in the policy bundle.
Response 200 OK
{ "provider": "openai", "disabled": true, "disabled_until": "2026-03-16T10:30:00Z"}POST /admin/api/providers/{provider}/enable
Section titled “POST /admin/api/providers/{provider}/enable”Re-enables a previously disabled provider. Clears the disable override immediately.
POST /admin/api/providers/{provider}/enableAuthorization: Bearer <token>No request body required.
Response 200 OK
{ "provider": "openai", "enabled": true}5. Credential Intelligence
Section titled “5. Credential Intelligence”CredInt uses a bloom filter to detect leaked credentials in prompts. These endpoints manage the filter state and k-anonymity verification.
GET /admin/api/credint/status
Section titled “GET /admin/api/credint/status”Returns bloom filter status: whether the filter is loaded, entry count, snapshot date, target false-positive rate, and file size.
GET /admin/api/credint/statusAuthorization: Bearer <token>Response 200 OK (filter loaded)
{ "enabled": true, "loaded": true, "entry_count": 847291054, "loaded_at": "2026-03-15T08:00:00Z", "file_size_bytes": 1073741824, "snapshot_date": "2026-03-01", "fpr_target": 0.001}Response 200 OK (filter not configured)
{ "enabled": false, "loaded": false, "entry_count": 0, "loaded_at": null, "file_size_bytes": 0, "snapshot_date": "", "fpr_target": 0.0}| Field | Type | Description |
|---|---|---|
entry_count |
integer | Number of entries in the bloom filter |
file_size_bytes |
integer | On-disk size of the bloom filter file |
snapshot_date |
string | Date of the credential snapshot |
fpr_target |
float | Target false-positive rate (e.g., 0.001 = 0.1%) |
POST /admin/api/credint/reload
Section titled “POST /admin/api/credint/reload”Reloads the CredInt bloom filter from the path configured in CREDINT_BLOOM_PATH. Hot-swaps the in-memory filter without an outpost restart.
POST /admin/api/credint/reloadAuthorization: Bearer <token>No request body required.
Response 200 OK (success)
{ "success": true, "message": "Bloom filter reloaded", "entry_count": 847291054}Response 200 OK (not configured)
{ "success": false, "message": "CredInt scanner not configured"}If reload fails (corrupt file, I/O error), the existing in-memory filter remains active (fail-open). Audit-logged as admin_credint_reload.
POST /admin/api/credint/kanon
Section titled “POST /admin/api/credint/kanon”Toggles k-anonymity verification on the CredInt scanner at runtime without a restart.
When k-anonymity is enabled (default), the outpost checks candidate credentials against the Have I Been Pwned k-anonymity API before surfacing a match. Disabling it suppresses those external checks — useful for air-gapped deployments.
Requires: Content-Type: application/json (returns 415 if missing).
Request body
{"enabled": true}| Field | Type | Required | Description |
|---|---|---|---|
enabled |
boolean | Yes | Enable or disable k-anonymity verification |
Response 200 OK
{"credint_kanon_enabled": true, "message": "K-anonymity enabled"}Response 503: {"detail": "Settings not initialised"}
6. Budget & Usage
Section titled “6. Budget & Usage”These endpoints provide visibility into token usage, estimated costs, and budget enforcement status for the current billing period.
GET /admin/api/usage
Section titled “GET /admin/api/usage”Returns the current-period usage summary from the outpost’s local usage tracker.
GET /admin/api/usageAuthorization: Bearer <token>Response 200 OK (tracking enabled)
{ "period_start": "2026-03-01T00:00:00Z", "period_end": "2026-03-31T23:59:59Z", "tokens_input": 1240000, "tokens_output": 890000, "total_requests": 3412, "estimated_cost_usd": 24.80, "budget_cap_usd": 500.00, "budget_remaining_usd": 475.20, "budget_alert_threshold_pct": 80}Response 200 OK (tracking disabled)
{ "usage_tracking": "disabled", "totals": null, "budget_config": null}GET /admin/api/budget/status
Section titled “GET /admin/api/budget/status”Current budget enforcement status for the active billing period. Reports spend against configured caps with percentage tracking.
curl -s http://outpost.internal:8301/admin/api/budget/status \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "period": "2026-03-01T00:00:00Z", "period_type": "monthly", "dollar_cap": 500.0, "dollar_spent": 312.847291, "dollar_percent": 62.57, "request_cap": 100000, "request_count": 67432, "request_percent": 67.43, "status": "ok", "warning": false}| Field | Values | Description |
|---|---|---|
status |
ok / warning / exceeded |
warning when ≥ 80% of either cap; exceeded when ≥ 100% |
warning |
bool | true when status is warning |
period_type |
monthly / hourly |
Billing period type from policy bundle |
If usage tracking is disabled, returns {"usage_tracking": "disabled", "status": "ok", "warning": false}.
GET /admin/api/budget/export.csv
Section titled “GET /admin/api/budget/export.csv”Export budget usage data as a downloadable CSV file. Returns up to 100,000 rows, newest-first. Writes an audit log event on each export.
curl -s http://outpost.internal:8301/admin/api/budget/export.csv \ -H "Authorization: Bearer $ADMIN_API_KEY" \ -o budget_usage_$(date +%Y%m%d).csvResponse — text/csv with Content-Disposition: attachment; filename=budget_usage.csv
CSV columns: date, model, provider, org_id, input_tokens, output_tokens, estimated_cost, period.
7. Certificate Management
Section titled “7. Certificate Management”The outpost operates two certificate contexts: mTLS certificates for the outpost-to-platform mutual TLS connection (/admin/api/cert/*), and TLS serving certificates for the outpost’s own HTTPS listener (/admin/api/certs/*).
GET /admin/api/cert/status
Section titled “GET /admin/api/cert/status”Returns mTLS certificate metadata and rotation daemon state.
curl -s "http://localhost:8301/admin/api/cert/status" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY"Response 200 OK
{ "cert_path": "certs/outpost.pem", "subject": "CN=outpost-prod-us-east.arbitex.ai", "issuer": "CN=Arbitex Outpost CA", "not_before": "2026-01-01T00:00:00Z", "not_after": "2026-06-30T00:00:00Z", "days_remaining": 106, "status": "amber", "last_check_at": "2026-03-15T10:00:00Z", "last_rotation_at": "2025-12-01T08:30:00Z", "consecutive_failures": 0, "total_rotations": 3, "needs_rotation": false, "rotation_state": "idle"}| Field | Type | Description |
|---|---|---|
status |
string | Traffic-light: green (>30 days), amber (7–30 days), red (<7 days or unreadable) |
consecutive_failures |
integer | Consecutive rotation failures |
total_rotations |
integer | Lifetime successful rotations |
If the cert rotation client is not configured, rotation fields return zero/null.
POST /admin/api/cert/renew
Section titled “POST /admin/api/cert/renew”Triggers an immediate mTLS certificate rotation cycle via the CertRotationClient (calls back to Platform’s cert issuance endpoint). Installs the new certificate without restarting.
curl -s -X POST "http://localhost:8301/admin/api/cert/renew" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY"Response 200 OK (rotated)
{"status": "renewed", "valid_until": "2026-09-30T00:00:00Z"}Response 200 OK (not needed)
{"success": false, "message": "no_renewal_needed"}Response 503: {"error": "Cert rotation client not configured"} or control plane unreachable.
Audit-logged as admin_cert_renew.
GET /admin/api/certs/status
Section titled “GET /admin/api/certs/status”Returns TLS serving certificate CN, expiry, and auto-rotation configuration.
Response 200 OK
{ "cert_path": "certs/outpost.pem", "cn": "outpost-prod.example.com", "expiry": "2026-12-31T00:00:00Z", "not_after": "2026-12-31T00:00:00Z", "days_remaining": 290, "needs_rotation": false, "threshold_days": 30, "auto_rotate_enabled": true}| Field | Type | Description |
|---|---|---|
needs_rotation |
boolean | True when days_remaining < threshold_days |
threshold_days |
integer | From CERT_ROTATION_THRESHOLD_DAYS (default 30) |
auto_rotate_enabled |
boolean | From CERT_AUTO_ROTATE setting |
POST /admin/api/certs/rotate
Section titled “POST /admin/api/certs/rotate”Rotates the TLS serving certificate. Accepts a PEM payload or generates a self-signed cert.
Requires: CERT_AUTO_ROTATE=true (returns 403 if disabled).
Request body (optional)
{ "cert_pem": "-----BEGIN CERTIFICATE-----\n...", "key_pem": "-----BEGIN PRIVATE KEY-----\n..."}If no body is provided, generates an RSA-2048 self-signed certificate (365-day validity). If cert_pem and key_pem are supplied, they are validated before writing.
Response 200 OK
{"status": "rotated", "cn": "outpost-prod.example.com", "expiry": "2027-03-16T00:00:00Z"}Response 400: {"error": "Invalid PEM data: ..."} — malformed cert or key
Response 403: {"error": "Certificate auto-rotation is disabled. Set CERT_AUTO_ROTATE=true."}
Response 500: {"error": "Failed to write cert files: ..."} — filesystem or dependency error
Writes to OUTPOST_CERT_PATH and OUTPOST_KEY_PATH. Audit-logged as admin_cert_rotate.
8. Audit & SIEM
Section titled “8. Audit & SIEM”These endpoints provide local audit visibility through multiple interfaces: the JSONL file-backed buffer, the in-memory ring buffer, HMAC chain integrity verification, SIEM direct sink status, audit queue management, and the persistent sync checkpoint.
GET /admin/api/audit-buffer
Section titled “GET /admin/api/audit-buffer”Returns the last 200 events from the local JSONL audit buffer on disk. Useful for immediate review without exporting to a SIEM.
GET /admin/api/audit-bufferAuthorization: Bearer <token>Response 200 OK
{ "events": [ { "timestamp": "2026-03-12T09:00:01Z", "action": "proxy_request", "user_id": "u-xyz", "provider": "anthropic", "model": "claude-sonnet-4-6", "dlp_result": "pass", "latency_ms": 210 } ], "total": 47}total reflects the number of events in the response (up to 200), not the total events in the file.
GET /admin/audit/recent
Section titled “GET /admin/audit/recent”Returns DLP scan events from the in-memory ring buffer (50-event capacity) with pagination.
Query parameters
| Parameter | Type | Default | Constraints |
|---|---|---|---|
limit |
integer | 50 | max 200 |
offset |
integer | 0 | — |
Response 200 OK
{ "events": [ { "event_id": "dlp_01HZ9KQBW4J8YQNXT3R6MFD2AE", "prev_event_id": "dlp_01HZ9KQBW4J8YQNXT3R6MFD29X", "hmac_signature": "a3f7...", "timestamp": "2026-03-15T10:23:44Z", "org_id": "org_abc", "action_taken": "BLOCK", "was_blocked": true, "was_redacted": false, "scan_duration_ms": 2.34, "entities_detected": [ {"type": "aws_access_key_id", "confidence": 0.98, "redacted": true} ], "entity_types_detected": ["CREDIT_CARD"], "request_body_hash": "sha256:ab12...", "response_body_hash": "sha256:cd34..." } ], "total": 847, "limit": 50, "offset": 0}GET /admin/audit/stats
Section titled “GET /admin/audit/stats”Returns aggregated DLP scan statistics since outpost startup.
Response 200 OK
{ "total_scans": 12450, "total_blocked": 34, "total_redacted": 127, "avg_scan_duration_ms": 8.7, "entity_type_counts": { "aws_access_key_id": 22, "credit_card": 89, "ssn": 41 }, "action_distribution": { "ALLOW": 12289, "BLOCK": 34, "REDACT": 127 }, "uptime_seconds": 86420, "scans_per_minute": 14.2}scans_per_minute is computed over a rolling 5-minute window. entity_type_counts and action_distribution are cumulative since startup.
GET /admin/audit/search
Section titled “GET /admin/audit/search”Searches DLP scan events in the ring buffer with filters. Filters are applied cumulatively (AND).
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
action |
string | — | Substring filter on action_taken (case-insensitive) |
entity_type |
string | — | Substring filter on detected entity types (case-insensitive) |
min_duration_ms |
float | — | Minimum scan_duration_ms |
blocked_only |
boolean | false | Filter to action_taken == "BLOCK" only (overrides action) |
limit |
integer | 20 | max 100 |
offset |
integer | 0 | — |
Response 200 OK
{ "events": [...], "total": 34, "limit": 20, "offset": 0}GET /admin/audit/verify
Section titled “GET /admin/audit/verify”Verifies HMAC chain integrity of the in-memory DLP scan ring buffer. Walks all events, recomputes HMACs, and checks prev_event_id chain linkage.
Response 200 OK (chain valid)
{ "valid": true, "events_checked": 847, "first_broken_at": null, "error": null}Response 200 OK (chain not enabled)
{ "valid": true, "events_checked": 0, "first_broken_at": null, "error": "Audit chain not enabled (AUDIT_CHAIN_ENABLED=false)"}Response 200 OK (chain broken)
{ "valid": false, "events_checked": 50, "first_broken_at": "a1b2c3d4-...", "error": null}first_broken_at is the event_id of the first event with a mismatched HMAC or broken chain link. The first event in the buffer is exempt from prev-chain checks (it may reference an evicted event).
GET /admin/api/audit/verify
Section titled “GET /admin/api/audit/verify”Extended variant with richer response schema. Also verifies the HMAC chain of the ring buffer, but additionally includes first_event_id and last_event_id for cross-referencing against platform audit records.
Response 200 OK (chain valid)
{ "verified": true, "total_events": 847, "first_event_id": "dlp_01HZ9KQBW4J8YQNXT3R6MFD100", "last_event_id": "dlp_01HZ9KQBW4J8YQNXT3R6MFD2AE", "chain_valid": true, "broken_at_event": null}Response 200 OK (chain broken)
{ "verified": false, "total_events": 50, "first_event_id": "a1b2c3d4-...", "last_event_id": "e5f6a7b8-...", "chain_valid": false, "broken_at_event": "c9d0e1f2-..."}When AUDIT_CHAIN_ENABLED=false, returns verified: true with a note field explaining the chain is not enabled.
GET /admin/api/audit-sync/checkpoint
Section titled “GET /admin/api/audit-sync/checkpoint”Return the current state of the audit write-ahead log (WAL), persistent sync checkpoint, and live sync worker. Useful for diagnosing audit delivery gaps after network disconnects or outpost restarts.
Response 200 OK
{ "wal": { "pending_entries": 12, "oldest_entry_at": "2026-03-16T13:55:00Z", "disk_usage_bytes": 24576, "wal_path": "/var/outpost/data/audit.wal" }, "checkpoint": { "last_synced_event_id": "dlp_01HZ9KQBW4J8YQNXT3R6MFD29X", "last_synced_at": "2026-03-16T14:05:00Z", "total_synced": 835 }, "sync_worker": { "running": true, "last_flush_at": "2026-03-16T14:05:00Z", "flush_interval_seconds": 30, "consecutive_failures": 0, "degraded": false }}| Field | Description |
|---|---|
wal.pending_entries |
Events written to WAL but not yet confirmed as synced to platform |
checkpoint.last_synced_event_id |
Event ID of the last successfully delivered audit event |
sync_worker.consecutive_failures |
Number of consecutive sync failures; triggers degradation mode |
Any of wal, checkpoint, or sync_worker may be null if that component is not configured.
GET /admin/api/siem/status
Section titled “GET /admin/api/siem/status”SIEM direct sink status: sink type, enablement state, event counters, and last error.
curl -s http://outpost.internal:8301/admin/api/siem/status \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK (SIEM enabled)
{ "enabled": true, "sink_type": "splunk_hec", "events_sent": 84320, "events_failed": 3, "last_error": "connection timeout after 10s", "last_flush_at": "2026-03-16T14:07:01Z"}Response 200 OK (SIEM disabled)
{ "enabled": false, "sink_type": null, "events_sent": 0, "events_failed": 0, "last_error": null, "last_flush_at": null}| Field | Type | Description |
|---|---|---|
sink_type |
string | null | "splunk", "splunk_hec", or "http" when enabled; null when disabled |
events_sent |
integer | Cumulative count of successfully forwarded events since process start |
events_failed |
integer | Cumulative count of events that failed to forward |
last_error |
string | null | Most recent forwarding error message, or null if no errors |
GET /admin/audit-queue/status
Section titled “GET /admin/audit-queue/status”Return current local audit queue statistics. The outpost writes audit events to a local SQLite queue during platform outages (circuit breaker open / degradation mode).
curl -s http://outpost.internal:8301/admin/audit-queue/status \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "count": 247, "oldest_queued_at": "2026-03-16T08:14:22Z", "disk_usage_bytes": 1048576, "degradation_mode": true}POST /admin/audit-queue/flush
Section titled “POST /admin/audit-queue/flush”Trigger an immediate flush of all queued audit events to the Platform, bypassing the regular sync interval.
curl -s -X POST http://outpost.internal:8301/admin/audit-queue/flush \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "flushed": 247, "failed": 0, "duration_ms": 382.1}Returns 409 Conflict if the queue is empty.
DELETE /admin/audit-queue/purge
Section titled “DELETE /admin/audit-queue/purge”Permanently discard all events in the local audit queue. Requires the X-Purge-Confirm: yes header to prevent accidental data loss.
curl -s -X DELETE http://outpost.internal:8301/admin/audit-queue/purge \ -H "Authorization: Bearer $ADMIN_API_KEY" \ -H "X-Purge-Confirm: yes"Response 200 OK
{"purged": 247}Returns 400 Bad Request if the X-Purge-Confirm: yes header is missing.
9. Configuration
Section titled “9. Configuration”These endpoints manage configuration export, backup/restore, diff/validate, hot-reload, and live key apply. Two config export variants are available: a structured JSON diagnostic export and a browser-downloadable backup file.
GET /admin/api/config/export
Section titled “GET /admin/api/config/export”Diagnostic config export — returns a structured JSON snapshot of the outpost’s effective runtime configuration. All secret and credential fields are replaced with "[REDACTED]". An admin_config_export entry is written to the local audit log.
curl -s http://outpost.internal:8301/admin/api/config/export \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "exported_at": "2026-03-15T12:10:00Z", "exported_by": "ops-admin", "runtime": { "log_level": "info", "listen_port": 8300, "admin_port": 8301, "admin_api_key": "[REDACTED]", "platform_url": "https://platform.arbitex.ai", "platform_mtls_cert": "/etc/outpost/certs/client.crt", "platform_mtls_key": "[REDACTED]" }, "airgap": { "airgap_enabled": false, "policy_path": "/etc/outpost/policy", "model_path": "/etc/outpost/models" }, "dlp": { "tier1_enabled": true, "tier2_enabled": true, "tier3_enabled": false, "ner_enabled": true, "deberta_enabled": false, "credint_enabled": true }, "siem": { "type": "splunk", "url": "https://splunk.corp.example.com:8088/services/collector", "token": "[REDACTED]", "buffer_capacity": 10000, "siem_output": true }, "geoip": { "city_mmdb_path": "/etc/outpost/geoip/GeoLite2-City.mmdb", "asn_mmdb_path": "/etc/outpost/geoip/GeoLite2-ASN.mmdb" }, "oauth": { "jwks_url": "https://platform.arbitex.ai/.well-known/jwks.json", "cache_ttl_seconds": 300, "scope_enforcement": true, "oauth_jwt_public_key": "[REDACTED]" }, "policy_bundle": { "loaded": true, "version": "2026.03.14-r1", "etag": "\"a3f9c2b1d4e5\"", "updated_at": "2026-03-14T06:00:00Z", "provider_count": 12, "dlp_rule_count": 34, "compliance_bundle_count": 4, "signature_valid": true }, "budget": { "daily_limit_usd": 500.00, "monthly_limit_usd": 12000.00, "enforcement": "block" }}| Section | Contents |
|---|---|
runtime |
All top-level config keys; secrets replaced with "[REDACTED]" |
airgap |
airgap_enabled, policy_path, model_path |
dlp |
Tier enablement flags and NER/DeBERTa/CredInt settings |
siem |
Type, URL, buffer capacity, output flag; SIEM token redacted |
geoip |
City and ASN MMDB file paths |
oauth |
JWKS URL, cache TTL, scope enforcement flag; JWT public key redacted |
policy_bundle |
Loaded state, version, etag, updated_at, provider/rule/compliance counts, signature validity |
budget |
Budget limits and enforcement mode from the loaded policy bundle (omitted if bundle not loaded) |
GET /admin/config/export
Section titled “GET /admin/config/export”Browser-download variant. Returns all non-secret configuration fields as a downloadable JSON file. The following fields are omitted entirely (rather than redacted): admin_api_key, provider_key_encryption_key, siem_direct_token, oauth_jwt_public_key.
curl -s http://outpost.internal:8301/admin/config/export \ -H "Authorization: Bearer $ADMIN_API_KEY"Response headers
Content-Type: application/jsonContent-Disposition: attachment; filename="outpost-config-backup-2026-03-15T12-10-00Z.json"The response body is the same shape as /admin/api/config/export but with secret fields omitted rather than redacted, and without the exported_by field.
POST /admin/api/config/backup
Section titled “POST /admin/api/config/backup”Create a JSON snapshot of the current running configuration. Secret fields are masked as "***". The snapshot is stored in an in-memory ring (last 10 backups) and optionally persisted to disk if BACKUP_DIR is configured.
Response 200 OK
{ "success": true, "timestamp": "2026-03-16T14:05:00Z", "fields": 42}fields is the count of configuration keys captured in the snapshot.
GET /admin/api/config/backup/list
Section titled “GET /admin/api/config/backup/list”List available config backups — timestamps and sizes (in-memory ring, up to 10 entries).
Response 200 OK
{ "backups": [ { "timestamp": "2026-03-16T14:05:00Z", "size": 2048 }, { "timestamp": "2026-03-16T12:00:00Z", "size": 2031 } ], "count": 2}Backups are stored in memory only (ring buffer, last 10). They do not persist across restarts unless BACKUP_DIR is set.
POST /admin/api/config/restore
Section titled “POST /admin/api/config/restore”Restore configuration from a backup payload. Secret fields in the payload are ignored and cannot be restored via this endpoint.
Request body
{ "config": { "log_level": "DEBUG", "policy_sync_interval": 60, "dlp_enabled": true }}Response 200 OK
{ "success": true, "applied": 3, "skipped": 0, "skipped_keys": []}Response 400 Bad Request: Unknown config keys in payload, or missing config key.
Fields masked as "***" in the payload are automatically skipped. Secret fields (audit_hmac_key, policy_hmac_key, outpost_api_key, etc.) are always skipped. Audit-logged as admin_config_restore.
POST /admin/config/diff
Section titled “POST /admin/config/diff”Compare a proposed configuration against the running settings. Read-only — does not modify any state.
Request body
{ "proposed_config": { "log_level": "DEBUG", "policy_sync_interval": 120 }}Response 200 OK
{ "changes": [ { "key": "log_level", "from": "INFO", "to": "DEBUG" }, { "key": "policy_sync_interval", "from": 60, "to": 120 } ], "change_count": 2, "has_breaking_changes": false, "summary": "2 changes: 2 modified"}has_breaking_changes is true if any changed key is in the breaking-change set (e.g., outpost_id, org_id, platform_management_url). All 26 configured settings fields are compared.
GET /admin/config/validate
Section titled “GET /admin/config/validate”Validate a proposed configuration JSON without applying it. Returns validation result, errors, warnings, and the diff against running settings.
Request body
{ "log_level": "DEBUG", "rate_limit_requests_per_minute": 0, "tls_min_version": "TLSv1.0"}Response 200 OK
{ "valid": false, "errors": [ "rate_limit_requests_per_minute must be > 0, got 0", "tls_min_version must be 'TLSv1.2' or 'TLSv1.3', got 'TLSv1.0'" ], "warnings": [], "changes": [ { "key": "log_level", "from": "INFO", "to": "DEBUG" } ]}Validation checks: rate-limit fields must be > 0; confidence/threshold fields must be 0–1; TLS cert paths must exist on disk; tls_min_version/tls_max_version must be "TLSv1.2" or "TLSv1.3". Unknown keys produce warnings, not errors.
GET /admin/api/config/reload-status
Section titled “GET /admin/api/config/reload-status”Return the timestamp and changed keys from the last config hot-reload.
curl -s http://outpost.internal:8301/admin/api/config/reload-status \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "last_reload_at": 1742137200.5, "last_reload_changes": [ "LOG_LEVEL: debug -> info", "DLP_NER_ENABLED: true -> false" ]}last_reload_at is a Unix timestamp. last_reload_changes lists changed keys with old → new values.
POST /admin/api/config/reload
Section titled “POST /admin/api/config/reload”Trigger a config hot-reload programmatically — equivalent to sending SIGHUP to the outpost process. Re-reads all reloadable environment keys and applies changes in-place. Writes an admin_config_reload audit event.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
dry_run |
bool | false | Compute diff and validate but do not apply changes |
# Preview what would changecurl -s -X POST "http://outpost.internal:8301/admin/api/config/reload?dry_run=true" \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "status": "ok", "changed_keys": ["LOG_LEVEL: debug -> info"], "restart_required_keys": [], "reloaded_at": 1742137200.5, "dry_run": false, "validation_errors": null}Response 422 Unprocessable Entity — pre-reload validation failed
{ "status": "rejected", "validation_errors": [ { "name": "AUDIT_HMAC_KEY", "status": "fail", "message": "AUDIT_HMAC_KEY must be at least 32 bytes" } ]}POST /admin/api/config/apply
Section titled “POST /admin/api/config/apply”Apply a single reloadable configuration key immediately without a restart. Only keys listed in RELOADABLE_KEYS can be applied at runtime. Non-reloadable keys (TLS cert paths, database URLs, crypto keys) require a full restart.
Request body
{"key": "log_level", "value": "DEBUG"}| Field | Type | Description |
|---|---|---|
key |
string | The OutpostSettings field name to update |
value |
string | New value — coerced to the field’s declared type |
Response 200 OK
{ "applied": true, "key": "log_level", "old_value": "INFO", "new_value": "DEBUG", "restart_required": false}Error responses
| Code | Condition |
|---|---|
400 |
Key not in RELOADABLE_KEYS, or missing key/value fields |
422 |
Value cannot be coerced to the field’s declared type |
Reloadable keys (common)
| Key | Type | Description |
|---|---|---|
log_level |
string | Logging level: DEBUG, INFO, WARNING, ERROR |
audit_flush_interval_seconds |
int | Audit queue flush interval |
credint_kanon_enabled |
bool | CredInt k-anonymity (also available via /admin/api/credint/kanon) |
heartbeat_interval_seconds |
int | Platform heartbeat frequency |
dlp_scan_timeout_ms |
int | DLP scan timeout per request |
budget_check_enabled |
bool | Enable/disable budget enforcement |
Sensitive values (api_key, secret, password, token) are redacted to *** in the response and audit trail. All applied changes are recorded in the config reload history ring buffer and written to the audit log.
GET /admin/api/config/reload-history
Section titled “GET /admin/api/config/reload-history”Return a paginated log of all config key changes applied via POST /admin/api/config/apply since startup.
Query parameters
| Parameter | Default | Maximum | Description |
|---|---|---|---|
limit |
20 | 50 | Entries per page |
offset |
0 | — | Pagination offset |
Response 200 OK
{ "entries": [ { "timestamp": 1742151720.4, "key": "log_level", "old_value": "INFO", "new_value": "DEBUG" }, { "timestamp": 1742151600.1, "key": "audit_flush_interval_seconds", "old_value": "30", "new_value": "10" } ], "total": 2, "limit": 20, "offset": 0}The history ring buffer is in-memory and resets on outpost restart. Sensitive values are always redacted to ***.
10. Multi-Org
Section titled “10. Multi-Org”Multi-org mode allows a single outpost to serve multiple organizations simultaneously. Enabled via MULTI_ORG_MODE=true. This section also covers the policy cache, which is closely tied to per-org policy management.
GET /admin/api/orgs
Section titled “GET /admin/api/orgs”Return org mode and active organisations.
Response 200 OK (single-org mode)
{ "mode": "single", "orgs": [ { "org_id": "org_abc", "last_seen": null, "request_count": 0 } ]}Response 200 OK (multi-org mode)
{ "mode": "multi", "max_orgs": 10, "active_orgs": 3, "orgs": [ { "org_id": "org_abc", "last_seen": "2026-03-16T14:00:00Z", "request_count": 842 }, { "org_id": "org_xyz", "last_seen": "2026-03-16T13:59:00Z", "request_count": 315 } ]}GET /admin/api/orgs/{org_id}/policy-status
Section titled “GET /admin/api/orgs/{org_id}/policy-status”Return policy status for a specific org in multi-org mode.
Path parameter: org_id — the org identifier.
Response 200 OK
{ "org_id": "org_abc", "policy_loaded": true, "last_fetched": "2026-03-16T13:55:00Z", "cache_hits": 412, "cache_misses": 23}Response 400 Bad Request: Outpost is not in multi-org mode (MULTI_ORG_MODE=false).
GET /admin/api/cache/stats
Section titled “GET /admin/api/cache/stats”Return policy cache statistics.
Response 200 OK
{ "entries": 42, "hit_count": 9821, "miss_count": 412, "hit_rate_percent": 95.97, "eviction_count": 18, "ttl_seconds": 300, "enabled": true}If the policy cache is not configured, all counters are zero and enabled is false.
POST /admin/api/cache/clear
Section titled “POST /admin/api/cache/clear”Clear all policy cache entries immediately.
Response 200 OK
{ "success": true, "cleared": 42}cleared is the number of entries that were removed.
11. Kill Switch & Drain
Section titled “11. Kill Switch & Drain”These endpoints provide immediate traffic control: the emergency kill switch halts all AI proxy traffic, drain mode enables graceful shutdown, routing overrides pin traffic to a specific provider, and prompt holds allow admin review of flagged requests.
POST /admin/api/emergency-kill
Section titled “POST /admin/api/emergency-kill”Activates or deactivates the emergency kill switch. When active, all LLM requests are rejected immediately with 503 — no DLP evaluation, no provider contact.
POST /admin/api/emergency-killAuthorization: Bearer <token>Content-Type: application/json
{ "active": true, "reason": "Security incident — halting all AI traffic"}| Field | Type | Required | Description |
|---|---|---|---|
active |
boolean | yes | true to activate, false to deactivate |
reason |
string | no | Reason logged to the audit trail |
Response 200 OK
{ "kill_switch_active": true, "activated_at": "2026-03-16T09:00:00Z", "reason": "Security incident — halting all AI traffic"}GET /admin/api/drain/status
Section titled “GET /admin/api/drain/status”Return graceful drain status. Draining mode is entered when the outpost is shutting down — no new requests are accepted and in-flight requests are allowed to complete.
Response 200 OK
{ "draining": false, "inflight_requests": 7, "drain_start_time": null}When draining is active, drain_start_time is an ISO 8601 timestamp and draining is true.
POST /admin/api/routing-override
Section titled “POST /admin/api/routing-override”Pins all traffic to a specific provider and optional model, or clears an existing routing override. Routing overrides are in-memory and reset on outpost restart.
POST /admin/api/routing-overrideAuthorization: Bearer <token>Content-Type: application/jsonTo set an override:
{ "provider": "anthropic", "model": "claude-haiku-4-5-20251001", "reason": "OpenAI outage — routing all traffic to Anthropic fallback"}To clear the routing override and restore policy-default routing:
{"provider": null}or:
{"clear": true}Response 200 OK
{ "override_active": true, "provider": "anthropic", "model": "claude-haiku-4-5-20251001", "set_at": "2026-03-16T09:05:00Z"}Returns 400 if the provider name is not in the policy bundle.
GET /admin/api/prompt-holds
Section titled “GET /admin/api/prompt-holds”Lists all prompt holds (pending and resolved). Prompt holds are raised when the DLP pipeline flags a request for human review. Holds are in-memory only and do not persist across outpost restarts.
GET /admin/api/prompt-holdsAuthorization: Bearer <token>Response 200 OK
{ "holds": [ { "hold_id": "hold_01J...", "user_id": "usr_01J...", "conversation_id": "conv_01J...", "status": "pending", "prompt_message": "Code generation requires confirmation.", "prompt_text_preview": "Write a Python script that...", "rule_ids": ["custom-secret-leak"], "created_at": "2026-03-16T09:10:00Z", "resolved_at": null, "resolved_by": null } ], "pending_count": 1}POST /admin/api/prompt-holds/{hold_id}/approve
Section titled “POST /admin/api/prompt-holds/{hold_id}/approve”Approves a pending prompt hold, forwarding the held request to the LLM.
POST /admin/api/prompt-holds/{hold_id}/approveAuthorization: Bearer <token>Returns 404 if the hold is not found or already resolved.
Response 200 OK
{"hold_id": "hold_01J...", "status": "approved", "resolved_at": "2026-03-16T09:11:00Z"}POST /admin/api/prompt-holds/{hold_id}/deny
Section titled “POST /admin/api/prompt-holds/{hold_id}/deny”Denies a pending prompt hold, returning an error to the requesting client.
POST /admin/api/prompt-holds/{hold_id}/denyAuthorization: Bearer <token>Returns 404 if the hold is not found or already resolved.
Response 200 OK
{"hold_id": "hold_01J...", "status": "denied", "resolved_at": "2026-03-16T09:11:00Z"}GET /admin/api/prompt-holds/events
Section titled “GET /admin/api/prompt-holds/events”Server-Sent Events (SSE) stream. Emits prompt_hold events in real time as new holds arrive. Backlogs all current pending holds on initial connect. Suitable for admin UI integrations.
curl -s -N "http://localhost:8301/admin/api/prompt-holds/events" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY" \ -H "Accept: text/event-stream"Event format
event: prompt_holddata: {"hold_id": "hold_01J...", "status": "pending", "created_at": "2026-03-16T09:10:00Z"}
event: prompt_hold_resolveddata: {"hold_id": "hold_01J...", "status": "approved", "resolved_at": "2026-03-16T09:11:00Z"}The stream remains open until the client disconnects.
POST /admin/api/prompt-holds/bulk-approve
Section titled “POST /admin/api/prompt-holds/bulk-approve”Approve multiple pending prompt holds in one request.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
hold_ids |
string[] | yes | List of hold IDs to approve |
curl -s -X POST \ http://outpost.internal:8301/admin/api/prompt-holds/bulk-approve \ -H "Authorization: Bearer $ADMIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hold_ids": ["hold_abc", "hold_def", "hold_ghi"]}'Response 200 OK
{ "results": { "hold_abc": true, "hold_def": true, "hold_ghi": false }, "approved_count": 2}results maps each hold ID to true (approved) or false (not found or already resolved). Writes an admin_bulk_approve_prompt_holds audit event.
12. Plugins & Webhooks
Section titled “12. Plugins & Webhooks”The plugin system allows optional extensions to be loaded at startup (e.g., custom DLP detectors, routing hooks). Enabled via PLUGINS_ENABLED=true. Plugins are discovered from PLUGIN_DIR (default ./plugins). Each plugin .py file must expose a register_plugin() function returning an object implementing the PluginInterface protocol.
GET /admin/api/plugins
Section titled “GET /admin/api/plugins”Lists all loaded plugins with their status.
Response 200 OK (plugins enabled)
{ "plugins_enabled": true, "plugins": [ { "name": "custom-redact-pii", "version": "1.2.0", "status": "enabled", "description": "Additional PII redaction patterns for EU deployments", "loaded_at": "2026-03-16T08:00:00Z", "hooks_registered": ["on_scan_complete", "on_startup", "on_shutdown"] }, { "name": "siem-forwarder-v2", "version": "0.9.1", "status": "disabled", "description": "Alternate SIEM forwarding with batching", "loaded_at": "2026-03-16T08:00:00Z" } ]}Response 200 OK (plugins not enabled)
{"plugins": [], "plugins_enabled": false}hooks_registered lists only hooks that are callable on the plugin instance.
POST /admin/api/plugins/{name}/enable
Section titled “POST /admin/api/plugins/{name}/enable”Enable a loaded plugin by name. Plugin name is case-sensitive and must match plugin.name.
Request body: {} (empty JSON; Content-Type: application/json required — returns 415 if missing)
Response 200 OK
{"status": "enabled", "name": "custom-redact-pii"}Response 404: {"detail": "Plugin 'custom-redact-pii' not found"}
Response 503: {"detail": "Plugin system not enabled"}
POST /admin/api/plugins/{name}/disable
Section titled “POST /admin/api/plugins/{name}/disable”Disable a loaded plugin by name.
Request body: {} (empty JSON required)
Response 200 OK
{"status": "disabled", "name": "custom-redact-pii"}Response 404: {"detail": "Plugin 'custom-redact-pii' not found"}
Response 503: {"detail": "Plugin system not enabled"}
GET /admin/api/webhook-emitter/stats
Section titled “GET /admin/api/webhook-emitter/stats”Returns webhook emitter statistics.
Response 200 OK (emitter configured)
{ "enabled": true, "events_queued": 12, "events_sent": 4821, "events_delivered": 4821, "events_failed": 3, "events_in_flight": 2, "last_delivered_at": "2026-03-16T09:01:00Z", "last_event_at": "2026-03-15T10:23:44.123456+00:00", "last_failure_at": "2026-03-15T22:14:00Z", "last_failure_reason": "HTTP 503 from webhook endpoint"}Response 200 OK (emitter not configured)
{ "enabled": false, "events_sent": 0, "events_failed": 0, "last_event_at": null}Configuration
| Setting | Description |
|---|---|
WEBHOOK_EMIT_ENABLED |
Master switch (default false) |
WEBHOOK_EMIT_URL |
Destination URL for webhook POSTs |
WEBHOOK_EMIT_SECRET |
HMAC-SHA256 signing secret |
Webhook payload format:
{ "event_type": "scan.complete", "org_id": "org_abc", "action": "BLOCK", "entity_types": ["CREDIT_CARD"], "scan_duration_ms": 2.1, "timestamp": "2026-03-15T10:23:44.123456+00:00"}The request includes an X-Webhook-Signature header containing the HMAC-SHA256 hex digest of the payload body. Retries up to 3 times with exponential backoff (1s, 2s). events_failed increments after all retries are exhausted.
13. Software Updates
Section titled “13. Software Updates”The outpost has two software update paths: the software update system (/admin/api/updates/*) manages downloading and staging update bundles for operator-applied container restarts, and the upgrade orchestrator (/admin/api/upgrade/*) manages the full automated lifecycle including apply and rollback.
GET /admin/api/updates/status
Section titled “GET /admin/api/updates/status”Return the current software update state: check result, download progress, staged version, and Ed25519 signature verification status. Requires SOFTWARE_UPDATE_RELEASE_URL to be configured.
Response 200 OK
{ "status": "staged", "current_version": "0.19.1", "latest_version": "0.19.2", "release_notes": "Fix: routing override not persisting across restarts", "download_progress": 100, "staged_at": "2026-03-16T14:22:00Z", "staged_version": "0.19.2", "staged_path": "/var/outpost/updates/outpost-0.19.2.tar.gz", "signature_verified": true, "error": null}| Field | Description |
|---|---|
status |
disabled | idle | checking | available | downloading | staged | error |
download_progress |
Integer 0–100. null until a download is in progress |
staged_path |
Filesystem path to the staged bundle. null if not yet staged |
signature_verified |
true when the Ed25519 bundle signature passed verification. null if not yet downloaded |
When SOFTWARE_UPDATE_RELEASE_URL is not set, status is "disabled" and error is "SOFTWARE_UPDATE_RELEASE_URL not configured".
POST /admin/api/updates/check
Section titled “POST /admin/api/updates/check”Trigger an immediate version check against the configured release manifest URL. Returns 503 if SOFTWARE_UPDATE_RELEASE_URL is not configured.
Response 200 OK
{ "update_available": true, "current_version": "0.19.1", "latest_version": "0.19.2", "release_notes": "Fix: routing override not persisting across restarts"}POST /admin/api/updates/download
Section titled “POST /admin/api/updates/download”Download and cryptographically verify the update bundle for the latest version. The bundle is verified against the embedded Ed25519 public key before being staged. Fail-closed: bundles with invalid signatures are rejected.
A staged update requires an operator-initiated apply (container restart with the new binary). There is no auto-apply path.
Returns 422 if signature verification fails.
Response 200 OK
{ "status": "staged", "staged_version": "0.19.2", "staged_path": "/var/outpost/updates/outpost-0.19.2.tar.gz", "signature_verified": true, "bytes_downloaded": 18432000}Response 422 Unprocessable Entity (signature failure)
{ "status": "error", "error": "Ed25519 signature verification failed — bundle rejected"}GET /admin/api/upgrade/status
Section titled “GET /admin/api/upgrade/status”Return the current upgrade orchestrator status.
curl -s "http://localhost:8301/admin/api/upgrade/status" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY"Response 200 OK
{ "phase": "idle", "last_result": "success", "last_upgraded_at": "2026-03-10T14:22:00Z", "current_version": "0.14.2", "history_count": 4}| Phase | Description |
|---|---|
idle |
No upgrade in progress |
checking |
Checking for available updates |
downloading |
Downloading update package |
verifying |
Verifying download signature |
backing_up |
Creating backup of current installation |
applying |
Applying the update |
post_verify |
Verifying the updated installation |
rolling_back |
Automatic rollback in progress |
POST /admin/api/upgrade/run
Section titled “POST /admin/api/upgrade/run”Execute the full upgrade lifecycle. The orchestrator runs all steps sequentially: check → download → verify → backup → apply → post-verify. On any step failure, the orchestrator automatically attempts to roll back.
Response 200 OK
{ "status": "success", "from_version": "0.14.1", "to_version": "0.14.2", "steps": [ {"step": "check", "result": "ok", "duration_ms": 1200}, {"step": "download", "result": "ok", "duration_ms": 8400}, {"step": "verify", "result": "ok", "duration_ms": 230}, {"step": "backup", "result": "ok", "duration_ms": 1100}, {"step": "apply", "result": "ok", "duration_ms": 3200}, {"step": "post_verify", "result": "ok", "duration_ms": 850} ]}Returns 409 Conflict if an upgrade is already in progress.
POST /admin/api/upgrade/rollback
Section titled “POST /admin/api/upgrade/rollback”Manually roll back the last staged upgrade. Use when upgrade/run failed without automatic rollback, or when a post-upgrade issue is discovered.
Response 200 OK
{"status": "rolled_back", "restored_version": "0.14.1"}GET /admin/api/upgrade/history
Section titled “GET /admin/api/upgrade/history”Return the last 10 upgrade run summaries.
Response 200 OK
[ { "run_id": "upg_01J...", "status": "success", "from_version": "0.14.1", "to_version": "0.14.2", "started_at": "2026-03-10T14:20:00Z", "completed_at": "2026-03-10T14:22:00Z" }]14. Operational Tools
Section titled “14. Operational Tools”These endpoints provide observability tooling: diagnostic bundles, metrics summaries, connection pool stats, circuit breakers, bandwidth adapter, DLP benchmarks, log export status, OpenTelemetry tracing status, Prometheus Pushgateway status, IP allowlist status, body hash config, and replay protection stats.
GET /admin/diagnostics
Section titled “GET /admin/diagnostics”Export a sanitized diagnostic bundle for support and troubleshooting. All secret fields (API keys, HMAC keys, signing keys) are scrubbed from the output. Safe to share with Arbitex support.
Response 200 OK
{ "generated_at": "2026-03-16T14:00:00Z", "version": "0.12.0", "uptime_seconds": 3600, "config_summary": { "outpost_id": "outpost-prod-01", "org_id": "org_abc", "platform_management_url": "https://api.arbitex.ai", "log_level": "INFO", "dlp_enabled": true, "credint_enabled": true, "admin_api_key": "***", "audit_hmac_key": "***" }, "audit_tail": [ { "event_id": "a1b2c3d4-...", "timestamp": "2026-03-16T13:58:00Z", "action_taken": "ALLOW" } ], "metrics": [ { "name": "outpost_requests_total", "count": 4821, "sum": 4821.0, "avg": 1.0 } ], "health_checks": [ { "check": "admin_key_set", "status": "pass", "message": "Admin API key configured" } ]}audit_tail contains the last 10 entries from the audit log file. config_summary omits all secret fields (shown as "***"). This endpoint writes an admin_diagnostics_export audit log entry.
GET /admin/api/metrics-summary
Section titled “GET /admin/api/metrics-summary”Return a JSON summary of the six custom OTel metrics with traffic-light status indicators, plus circuit breaker states. Returns 503 if prometheus-client is not installed.
Response 200 OK
{ "metrics": [ { "name": "outpost_requests_total", "display_name": "Total Requests", "unit": "requests", "status": "green", "display_value": 4821.0, "count": 4821, "sum": 4821.0, "avg": 1.0 }, { "name": "outpost_platform_reachable", "display_name": "Platform Reachable", "unit": "bool", "status": "green", "display_value": 1.0, "value": 1.0 } ], "metric_count": 7, "circuit_breakers": [ { "name": "platform_sync", "state": "closed", "status": "green" } ]}Traffic-light values: "green" (healthy), "yellow" (warning threshold), "red" (critical threshold). Histograms report count, sum, avg. Gauges report value. The synthetic outpost_platform_reachable metric reflects degradation manager state — 1.0 = reachable, 0.0 = degraded.
GET /admin/api/metrics/connections
Section titled “GET /admin/api/metrics/connections”HTTP connection pool statistics for the outpost proxy.
curl -s http://outpost.internal:8301/admin/api/metrics/connections \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "active_connections": 12, "idle_connections": 28, "max_connections": 200, "pool_started": true}GET /admin/api/circuit-breakers
Section titled “GET /admin/api/circuit-breakers”List the state of every registered circuit breaker — both provider-level and per-model breakers.
curl -s http://outpost.internal:8301/admin/api/circuit-breakers \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "circuit_breakers": [ { "name": "anthropic", "state": "closed", "failure_count": 0, "success_count": 8421, "last_failure": null }, { "name": "openai:gpt-4o", "state": "half_open", "failure_count": 3, "success_count": 7, "last_failure": 1742137190.3 } ]}States: closed (normal), open (blocking requests), half_open (testing recovery).
GET /admin/api/bandwidth
Section titled “GET /admin/api/bandwidth”Bandwidth adapter statistics: throughput measurement, window sizing, and recommended audit batch size.
curl -s http://outpost.internal:8301/admin/api/bandwidth \ -H "Authorization: Bearer $ADMIN_API_KEY"Response 200 OK
{ "enabled": true, "throughput_bps": 1048576, "window_size": 50, "window_capacity": 100, "recommended_batch_size": 50, "tier_name": "standard", "batch_min": 10, "batch_max": 100, "connection_health_status": "healthy"}Returns {"enabled": false, ...} when the bandwidth adapter is not configured.
GET /admin/api/benchmarks
Section titled “GET /admin/api/benchmarks”Return DLP pipeline benchmark results from the most recent benchmark run.
Response 200 OK
{ "run_at": "2026-03-15T08:00:00Z", "pipeline": "5-tier", "total_samples": 1000, "avg_latency_ms": 2.34, "p95_latency_ms": 6.12, "p99_latency_ms": 11.45, "tier_breakdown": { "tier0_tfidf": { "avg_ms": 0.08, "p95_ms": 0.15 }, "tier1_regex": { "avg_ms": 0.21, "p95_ms": 0.45 }, "tier2_ner": { "avg_ms": 1.87, "p95_ms": 4.92 }, "tier3_deberta": { "avg_ms": 8.43, "p95_ms": 18.20 }, "tier4_credint": { "avg_ms": 0.34, "p95_ms": 0.72 } }}Response 404 Not Found: No benchmark results on disk — run benchmarks/dlp_pipeline_bench.py first.
GET /admin/api/log-export/status
Section titled “GET /admin/api/log-export/status”Return log export status (file-based structured log export).
Response 200 OK
{ "enabled": true, "path": "/var/log/arbitex/outpost", "format": "jsonl", "current_file_size_bytes": 204800, "total_files": 7, "oldest_file": "2026-03-10T00:00:00Z", "newest_file": "2026-03-16T14:00:00Z"}If log export is not configured, enabled is false and all other fields are empty/zero defaults.
GET /admin/api/otel/status
Section titled “GET /admin/api/otel/status”Return OpenTelemetry tracing status.
Response 200 OK
{ "enabled": true, "endpoint": "http://otel-collector:4317", "service_name": "arbitex-outpost", "export_protocol": "grpc", "spans_exported": 12450, "export_errors": 0}If OTel is not configured, enabled is false.
GET /admin/api/pushgateway/status
Section titled “GET /admin/api/pushgateway/status”Return Prometheus Pushgateway exporter status.
Response 200 OK
{ "enabled": true, "url": "http://pushgateway:9091", "job": "outpost", "instance": "outpost-prod-01", "last_push_at": "2026-03-16T13:59:55Z", "last_push_status": "success", "consecutive_failures": 0, "is_circuit_open": false}If the Pushgateway exporter is not configured, enabled is false and all other fields are empty/zero defaults.
GET /admin/api/ip-allowlist/status
Section titled “GET /admin/api/ip-allowlist/status”Return IP allowlist configuration and denied request count since startup.
Response 200 OK
{ "enabled": true, "cidrs": ["10.0.0.0/8", "192.168.1.0/24"], "admin_exempt": true, "denied_count": 12}admin_exempt indicates whether the admin API (port 8301) is exempt from IP allowlist enforcement. When the allowlist is disabled (IP_ALLOWLIST_ENABLED=false), enabled is false and cidrs is an empty array.
GET /admin/api/body-hash/config
Section titled “GET /admin/api/body-hash/config”Return body hash logging configuration. Body hash logging writes HMAC-SHA256 hashes of request/response bodies into the DLP scan audit events. Enabled via BODY_HASH_LOGGING_ENABLED=true.
Response 200 OK
{ "enabled": true, "algorithm": "sha256", "log_response": false, "key_source": "audit_hmac_key"}| Field | Values |
|---|---|
algorithm |
"sha256" (default) |
log_response |
true = response body is also hashed; false = request body only |
key_source |
"audit_hmac_key" | "admin_jwt_secret" | "not_configured" |
GET /admin/api/replay-protection/stats
Section titled “GET /admin/api/replay-protection/stats”Return replay protection cache statistics.
Response 200 OK
{ "enabled": true, "cache_size": 248, "duplicates_blocked": 3}Replay protection rejects duplicate requests (same X-Request-ID) within the protection window. When disabled (REPLAY_PROTECTION_ENABLED=false), enabled is false and counters are zero.
Error Responses
Section titled “Error Responses”| Status | Cause |
|---|---|
400 |
Bad request — missing or invalid field |
401 |
Missing Authorization header, or empty token |
403 |
Invalid admin API key, or operation not permitted |
404 |
Resource not found (provider, rule, hold, etc.) |
409 |
Conflict (duplicate request ID, upgrade already in progress, empty queue flush) |
415 |
Missing Content-Type: application/json |
422 |
Validation error (type coercion failure, bundle validation) |
429 |
Brute-force rate limit exceeded — 5 failed auth attempts within 15 minutes |
500 |
Unhandled server error or uninitialised component |
503 |
Required component not initialised (e.g. no policy bundle loaded) |
See also
Section titled “See also”- Outpost architecture overview — port layout and admin network isolation
- Credential Intelligence guide — bloom filter setup and CDN refresh
- Policy Simulator guide — detailed simulate response schema
- DLP Rules API reference — rule and ruleset IDs
- Outpost deployment guide — Kubernetes installation and initial configuration
- Outpost certificate management — Certificate rotation procedures
- PROMPT governance guide — How PROMPT holds are created and managed
- Audit Chain Integrity — HMAC chain design and verification