REST API Reference
Complete reference for the AEGIS Governance REST API including evaluate, risk-check, health, and customer management endpoints.
Base URL
| Environment | URL |
|---|---|
| Dev | https://aegis-api-980022636831.us-central1.run.app |
| Prod | Contact your administrator for the production endpoint |
Authentication
All endpoints except /health require an API key passed as a Bearer
token in the Authorization header:
Authorization: Bearer YOUR_API_KEYThe key is issued during onboarding and maps to a customer ID
(cust_...) that is included in every response for audit trail
correlation.
Rate Limits
Rate limiting operates at two layers:
Per-key limits (enforced by Unkey, based on your tier):
| Tier | Rate | Monthly evaluations |
|---|---|---|
| Community | 60 req/min | 100 |
| Professional | 100 req/min | 10,000 |
| Enterprise | 1,000 req/min | 100,000 |
| Financial Services | 2,000 req/min | 250,000 |
Platform ceiling (API Gateway usage plan limits, rarely encountered):
| Environment | Sustained | Burst | Daily quota |
|---|---|---|---|
| Dev | 50 req/s | 25 req/s | 10,000 |
| Prod | 500 req/s | 250 req/s | 500,000 |
Exceeding your per-key rate limit returns HTTP 429 Too Many Requests.
Response Headers
Every response includes the following custom headers:
| Header | Description |
|---|---|
X-AEGIS-Version | AEGIS package version (e.g., 1.1.0) |
X-AEGIS-Tenant | Customer ID derived from the API key (anonymous if unauthenticated) |
X-AEGIS-Customer | Customer ID (format: cust_...). Present only for authenticated requests. |
X-AEGIS-Tier | Customer tier name. Present only for authenticated requests. |
X-AEGIS-Rate-Remaining | Remaining requests in the current rate-limit window. Present only when Unkey rate-limiting is active. |
X-AEGIS-Request-Id | Unique request identifier for support and log correlation |
Access-Control-Allow-Origin | Restricted to portal.undercurrentholdings.com and undercurrentholdings.com origins (plus Vercel preview URLs) |
Access-Control-Allow-Headers | Content-Type,Authorization,X-Api-Key |
Access-Control-Allow-Methods | POST,GET,PATCH,DELETE,OPTIONS |
Architecture
The REST API is served by a FastAPI application on GCP Cloud Run:
| Service | Endpoints | Source | Auth |
|---|---|---|---|
| aegis-api (Cloud Run) | /evaluate, /risk-check, /health, /customer/*, /webhooks/stripe | src/api_server.py | Bearer API key (Unkey) |
Customer routes delegate to handlers in src/aegis_governance/customer_api.py.
Authentication is handled by src/aegis_governance/cloud_run_auth.py.
Sandbox Evaluation
POST /sandbox/evaluate
Evaluate a proposal without authentication. Rate limited to 10 evaluations per IP per day (in-memory, resets on instance restart).
Authentication: None required.
Request body: Same as POST /evaluate (see below).
Response: Same Decision shape as POST /evaluate, plus:
| Field | Type | Description |
|---|---|---|
sandbox | boolean | Always true for sandbox evaluations |
remaining | integer | Evaluations remaining today for this IP |
Rate limit response (HTTP 429):
{
"error": "sandbox_limit_reached",
"limit": 10,
"remaining": 0,
"message": "Sandbox limit reached (10/day). Get a free API key at https://portal.undercurrentholdings.com for 100/month.",
"upgrade_url": "https://portal.undercurrentholdings.com"
}Sandbox evaluations are not persisted, billed, or included in audit chains.
Governance Evaluation Endpoints
POST /evaluate
Evaluate a proposal through all six AEGIS governance gates.
The HTTP status code is always 200 for structurally valid requests.
The governance outcome is conveyed by the status field in the response
body.
Request Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
proposal_summary | string | No | "API evaluation" | Human-readable summary of the proposed change. |
estimated_impact | string | No | "medium" | Expected blast radius. One of low, medium, high, critical. Proposals marked high or critical always require human approval regardless of gate outcomes. |
agent_id | string | No | "api-caller" | Identifier of the calling agent or service. Logged in the audit trail. |
session_id | string | No | Auto-generated UUID | Client-supplied session identifier for grouping related evaluations. |
phase | string | No | "plan" | Current PCW lifecycle phase. One of plan, commit, work. Affects the next_steps remediation guidance. |
risk_baseline | number | No | 0.0 | Current (pre-change) risk level. Must be finite. |
risk_proposed | number | No | 0.0 | Projected risk level after the change. Must be finite. |
risk_score | number | No | -- | Alias for risk_proposed. Used only when risk_proposed is not provided. |
profit_baseline | number | No | 0.0 | Current (pre-change) profit metric. Must be finite. |
profit_proposed | number | No | 0.0 | Projected profit metric after the change. Must be finite. |
novelty_score | number | No | 0.5 | Novelty score (0-1). Higher values indicate more novel proposals. Must be finite. |
complexity_score | number | No | 0.5 | Complexity score (0-1). Must exceed the complexity floor to pass the gate. Must be finite. |
quality_score | number | No | 0.7 | Aggregate quality score (0-1). Must be finite. |
quality_subscores | array of numbers | No | [0.7, 0.7, 0.7] | Per-dimension quality scores. null elements are filtered out. An explicit empty array [] is preserved (quality gate may fail). An array of all null values falls back to the default [0.7, 0.7, 0.7]. Elements must be finite numbers (not booleans). |
requires_human_approval | boolean | No | false | Force human-approval escalation even when all gates pass. Must be a boolean (non-boolean types are rejected). |
time_sensitive | boolean | No | false | Flag indicating a time-sensitive proposal. Must be a boolean. |
reversible | boolean | No | true | Whether the proposed change can be rolled back. Irreversible changes always require human approval. Must be a boolean. |
metadata | object | No | {} | Arbitrary key-value pairs attached to the audit trail. Must be a JSON object. |
shadow_mode | boolean | No | false | When true, gates evaluate normally but drift is recorded for calibration only -- decisions are not enforced. Must be a boolean. Requires Professional tier or higher (Community tier returns 403). |
change_type | string | No | "feature" | Type of change: feature, refactor, bugfix, config. Non-feature types skip novelty and profit gates. |
drift_baseline_data | array of numbers | No | -- | Array of historical numeric observations used to seed the drift monitor baseline. null elements are filtered out. Each element must be a finite number (not a boolean). |
Response Fields
| Field | Type | Always present | Description |
|---|---|---|---|
status | string | Yes | Governance outcome: proceed, pause, halt, or escalate. |
confidence | number or null | Yes | Minimum confidence across all gates (0-1). null if non-finite. |
gates_passed | integer | Yes | Number of gates that passed. |
gates_failed | integer | Yes | Number of gates that failed. |
failing_gates | array of strings | Yes | Names of the gates that failed. Possible values: risk, profit, novelty, complexity, quality, utility. |
rationale | string | Yes | Human-readable explanation of the decision. |
next_steps | array of strings | Yes | Recommended actions based on decision status and current phase. |
constraints | array of strings | Yes | Active constraints (e.g., complexity floor not met, drift warnings). |
decision_id | string (UUID) | Yes | Unique identifier for this decision. Use this for audit trail lookups. |
timestamp | string (ISO 8601) | Yes | UTC timestamp of the decision. |
override_eligible | boolean | Yes | Whether the decision may be overridden with two-key approval. Always false when the complexity floor fails or critical drift is detected. |
override_requires | array of strings | Yes | Roles required to approve an override (e.g., risk_lead, security_lead). Empty when override_eligible is false. |
gates | object | When gates evaluated | Per-gate evaluation details. Each key is a gate name; see Gate Detail below. |
drift | object | When drift detected | Drift policy enforcement result. See Drift Detail below. |
shadow_result | object | When shadow_mode is true | Shadow mode evaluation metadata. See Shadow Detail below. |
_tenant_id | string | Yes | Customer identifier derived from the API key (anonymous if unauthenticated). |
_customer_id | string | When authenticated | Customer identifier (format: cust_...). Same value as _tenant_id for Unkey-authenticated requests. |
_tier | string | When authenticated | Customer tier: community, professional, enterprise, or financial_services. |
_request_id | string | Yes | Unique request identifier for correlation. |
Gate Detail
Each entry in the gates object has the following shape:
| Field | Type | Description |
|---|---|---|
passed | boolean | Whether this gate passed. |
value | number or null | Computed gate value (rounded to 6 decimal places). null if non-finite. |
threshold | number or null | Threshold used for the gate decision. null if non-finite. |
confidence | number or null | Bayesian confidence score. Present for risk and profit gates; null for other gates. |
message | string or null | Optional diagnostic message. |
The six gates are:
| Gate | What it measures |
|---|---|
risk | Bayesian posterior P(delta-risk >= 2 | data) against 0.95 threshold |
profit | Bayesian posterior P(delta-profit >= 2 | data) against 0.95 threshold |
novelty | Logistic function G(N) for novelty assessment |
complexity | Hard floor -- proposal must meet minimum complexity score |
quality | Aggregate quality score against threshold |
utility | Lower confidence bound (LCB) of expected utility against threshold |
Drift Detail
Present only when drift policy enforcement detects non-normal drift:
| Field | Type | Description |
|---|---|---|
status | string | Drift severity: normal, warning, or critical. |
kl_divergence | number or null | KL divergence between current observations and baseline. |
action | string | Recommended action: continue, alert_and_continue, or halt_and_recalibrate. |
message | string or null | Diagnostic message. |
Critical drift upgrades the decision to halt and sets
override_eligible to false.
Shadow Detail
Present only when shadow_mode is true:
| Field | Type | Description |
|---|---|---|
shadow_only | boolean | Always true in shadow mode. |
observation_values | array of numbers | Computed deltas [risk_proposed - risk_baseline, profit_proposed - profit_baseline]. |
baseline_hash | string or null | SHA-256 hash of the drift baseline (for auditability). |
drift | object or null | Drift evaluation result (same shape as Drift Detail). |
Decision Status Logic
The status is determined by the following priority rules:
- All gates pass and no human approval required --
proceed - All gates pass but high/critical impact --
escalate - All gates pass but human approval required --
pause - Complexity floor fails --
halt(non-overridable) - Critical drift detected --
halt(non-overridable) - Gates fail with high/critical impact --
escalate - Gates fail with human approval required --
pause - Gates fail otherwise --
pause
Example
curl -s -X POST \
https://aegis-api-980022636831.us-central1.run.app/evaluate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"proposal_summary": "Add caching layer to reduce API latency",
"estimated_impact": "medium",
"risk_baseline": 0.05,
"risk_proposed": 0.08,
"profit_baseline": 0.10,
"profit_proposed": 0.18,
"complexity_score": 0.4,
"quality_score": 0.85
}' | python3 -m json.toolPOST /risk-check
Quick risk threshold check. Performs a simple risk_score < threshold
comparison without invoking the full Bayesian gate pipeline.
Warning: This endpoint does NOT compute posterior probabilities, does
not evaluate any gates, and does not generate an audit trail. For
auditable governance decisions, use POST /evaluate.
Request Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
risk_score | number | Yes | -- | Estimated risk score to evaluate. Must be finite. Must not be a boolean. |
threshold | number | No | 0.5 | Risk threshold. The action is safe when risk_score < threshold. Must be finite. Must not be a boolean. |
agent_id | string | No | "api-caller" | Identifier of the calling agent. |
action_description | string | No | "Lambda risk check" | Brief description of the action being checked. |
Response Fields
| Field | Type | Always present | Description |
|---|---|---|---|
safe | boolean | Yes | true when risk_score < threshold. |
risk_score | number | Yes | The evaluated risk score (echoed back). |
threshold | number | Yes | The threshold used (echoed back). |
agent_id | string | Yes | The agent ID used (echoed back). |
_tenant_id | string | Yes | Customer identifier derived from the API key (anonymous if unauthenticated). |
_customer_id | string | When authenticated | Customer identifier (format: cust_...). Same value as _tenant_id for Unkey-authenticated requests. |
_tier | string | When authenticated | Customer tier: community, professional, enterprise, or financial_services. |
_request_id | string | Yes | Unique request identifier. |
Example
curl -s -X POST \
https://aegis-api-980022636831.us-central1.run.app/risk-check \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"risk_score": 0.35,
"threshold": 0.5,
"agent_id": "deploy-bot",
"action_description": "Deploy canary to staging"
}' | python3 -m json.toolResponse:
{
"safe": true,
"risk_score": 0.35,
"threshold": 0.5,
"agent_id": "deploy-bot",
"_tenant_id": "cust_a1b2c3d4e5f6",
"_customer_id": "cust_a1b2c3d4e5f6",
"_tier": "community",
"_request_id": "req-789"
}GET /health
Health check endpoint. Does not require authentication and is suitable for load-balancer or Kubernetes liveness probes.
Response Fields
| Field | Type | Description |
|---|---|---|
status | string | ok when all subsystems are healthy; degraded otherwise. |
version | string | AEGIS package version. |
stage | string | Deployment stage (dev, staging, prod, or unknown). |
checks | object | Per-subsystem health status. |
checks.config.ok | boolean | true if configuration loads successfully. |
checks.gates.ok | boolean | true if the gate evaluator initializes and runs a test evaluation. |
HTTP Status Codes
| Code | Meaning |
|---|---|
200 | All subsystems healthy. |
503 | One or more subsystems degraded. |
Example
curl -s https://aegis-api-980022636831.us-central1.run.app/health \
| python3 -m json.toolCustomer Management Endpoints
GET /customer/decisions
List governance decisions for the authenticated customer. Returns recent decisions with status, confidence, and gate summaries.
Request Parameters (Query String)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
month | string | No | Current month | Filter by month in YYYY-MM format. |
limit | integer | No | 50 | Maximum number of decisions to return (max 200). |
Response Fields
| Field | Type | Always present | Description |
|---|---|---|---|
decisions | array | Yes | Array of decision summary objects. |
decisions[].decision_id | string (UUID) | Yes | Unique decision identifier. |
decisions[].status | string | Yes | Governance outcome: proceed, pause, halt, escalate. |
decisions[].confidence | number or null | Yes | Minimum confidence across all gates. |
decisions[].proposal_summary | string | Yes | Brief description of the proposal. |
decisions[].timestamp | string (ISO 8601) | Yes | UTC timestamp of the decision. |
decisions[].gates_passed | integer | Yes | Number of gates that passed. |
decisions[].gates_failed | integer | Yes | Number of gates that failed. |
total | integer | Yes | Total decisions matching the filter. |
month | string | Yes | The YYYY-MM filter applied. |
_customer_id | string | Yes | Customer identifier. |
_request_id | string | Yes | Unique request identifier. |
Example
curl -s \
"https://aegis-api-980022636831.us-central1.run.app/customer/decisions?month=2026-03&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY" \
| python3 -m json.toolGET /customer/decisions/{decision_id}
Get a specific governance decision by ID. Returns the full decision record including input context, all gate results, rationale, next steps, and audit hash.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
decision_id | string (UUID) | Yes | The unique decision identifier. |
Request Parameters (Query String)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
month | string | No | Current month | YYYY-MM of the decision (improves lookup performance). |
Response Fields
| Field | Type | Always present | Description |
|---|---|---|---|
decision_id | string (UUID) | Yes | Unique decision identifier. |
status | string | Yes | Governance outcome: proceed, pause, halt, escalate. |
confidence | number or null | Yes | Minimum confidence across all gates. |
proposal_summary | string | Yes | Brief description of the proposal. |
estimated_impact | string | Yes | Impact level. |
timestamp | string (ISO 8601) | Yes | UTC timestamp. |
rationale | string | Yes | Human-readable explanation of the decision. |
next_steps | array of strings | Yes | Recommended actions. |
gates | object | Yes | Per-gate evaluation details. |
constraints | array of strings | Yes | Active constraints. |
override_eligible | boolean | Yes | Whether override is possible. |
override_requires | array of strings | Yes | Roles needed for override. |
audit_hash | string | Yes | SHA-256 hash of the decision record. |
input_context | object | Yes | Original input parameters. |
_customer_id | string | Yes | Customer identifier. |
_request_id | string | Yes | Unique request identifier. |
Example
curl -s \
"https://aegis-api-980022636831.us-central1.run.app/customer/decisions/d4e5f6a7-b8c9-4d0e-a1f2-b3c4d5e6f7a8?month=2026-03" \
-H "Authorization: Bearer YOUR_API_KEY" \
| python3 -m json.toolGET /customer/decisions/export
Export governance decisions as JSON or CSV. Useful for compliance reporting and audit trail extraction.
Request Parameters (Query String)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
format | string | No | "json" | Export format: json or csv. |
month | string | No | Current month | Filter by month in YYYY-MM format. |
Response
- JSON format (
format=json): ReturnsContent-Type: application/jsonwith the same structure asGET /customer/decisions. - CSV format (
format=csv): ReturnsContent-Type: text/csvwith columns:decision_id,status,confidence,proposal_summary,timestamp,gates_passed,gates_failed.
Example
# JSON export
curl -s \
"https://aegis-api-980022636831.us-central1.run.app/customer/decisions/export?format=json&month=2026-03" \
-H "Authorization: Bearer YOUR_API_KEY" \
| python3 -m json.tool
# CSV export
curl -s \
"https://aegis-api-980022636831.us-central1.run.app/customer/decisions/export?format=csv&month=2026-03" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o decisions-2026-03.csvError Codes
All error responses have a consistent JSON shape:
{
"error": "Human-readable error message"
}| HTTP Code | Meaning | Common causes |
|---|---|---|
400 | Bad Request | Invalid JSON body, missing required field (risk_score for /risk-check), non-finite numeric value (Inf, NaN), boolean where number expected, non-object metadata, non-list quality_subscores, non-boolean shadow_mode. |
403 | Forbidden | Missing or invalid Authorization: Bearer token. |
404 | Not Found | Unknown path or wrong HTTP method (e.g., GET /evaluate). |
429 | Too Many Requests | Rate limit exceeded. |
500 | Internal Server Error | Configuration error, evaluation engine failure. |
503 | Service Unavailable | One or more subsystems degraded (returned by /health only). |
Validation Details
The API performs strict input validation:
- Boolean fields (
requires_human_approval,time_sensitive,reversible,shadow_mode) must be JSON booleans (true/false). Strings, integers, andnullare rejected with HTTP 400. - Numeric fields must be finite (
Inf,-Inf, andNaNare rejected). Boolean values in numeric fields are also rejected (Pythonisinstance(True, int)isTrue, so the API guards against this explicitly). risk_scorein/risk-checkis required. All other numeric fields in/evaluateare optional with defaults.quality_subscoresmust be a JSON array when present. Each element must be a finite number ornull(booleans are rejected).metadatamust be a JSON object (not an array, string, or number).drift_baseline_dataelements must be finite numbers (booleans are rejected,nullelements are filtered out).estimated_impactmust be a string when present. Non-string types are rejected.
See Also
- OpenAPI Specification -- machine-readable API contract (OpenAPI 3.1.0)
- REST API Quickstart -- get started in 5 minutes
- Parameter Reference -- parameter derivation guidance
- Domain Templates -- trading, CI/CD, moderation, agent templates
- Production Guide -- deployment, observability, HSM configuration