AEGISdocs
API Reference

REST API Reference

Complete reference for the AEGIS Governance REST API including evaluate, risk-check, health, and customer management endpoints.

Base URL

EnvironmentURL
Devhttps://aegis-api-980022636831.us-central1.run.app
ProdContact 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_KEY

The 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):

TierRateMonthly evaluations
Community60 req/min100
Professional100 req/min10,000
Enterprise1,000 req/min100,000
Financial Services2,000 req/min250,000

Platform ceiling (API Gateway usage plan limits, rarely encountered):

EnvironmentSustainedBurstDaily quota
Dev50 req/s25 req/s10,000
Prod500 req/s250 req/s500,000

Exceeding your per-key rate limit returns HTTP 429 Too Many Requests.

Response Headers

Every response includes the following custom headers:

HeaderDescription
X-AEGIS-VersionAEGIS package version (e.g., 1.1.0)
X-AEGIS-TenantCustomer ID derived from the API key (anonymous if unauthenticated)
X-AEGIS-CustomerCustomer ID (format: cust_...). Present only for authenticated requests.
X-AEGIS-TierCustomer tier name. Present only for authenticated requests.
X-AEGIS-Rate-RemainingRemaining requests in the current rate-limit window. Present only when Unkey rate-limiting is active.
X-AEGIS-Request-IdUnique request identifier for support and log correlation
Access-Control-Allow-OriginRestricted to portal.undercurrentholdings.com and undercurrentholdings.com origins (plus Vercel preview URLs)
Access-Control-Allow-HeadersContent-Type,Authorization,X-Api-Key
Access-Control-Allow-MethodsPOST,GET,PATCH,DELETE,OPTIONS

Architecture

The REST API is served by a FastAPI application on GCP Cloud Run:

ServiceEndpointsSourceAuth
aegis-api (Cloud Run)/evaluate, /risk-check, /health, /customer/*, /webhooks/stripesrc/api_server.pyBearer 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:

FieldTypeDescription
sandboxbooleanAlways true for sandbox evaluations
remainingintegerEvaluations 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

FieldTypeRequiredDefaultDescription
proposal_summarystringNo"API evaluation"Human-readable summary of the proposed change.
estimated_impactstringNo"medium"Expected blast radius. One of low, medium, high, critical. Proposals marked high or critical always require human approval regardless of gate outcomes.
agent_idstringNo"api-caller"Identifier of the calling agent or service. Logged in the audit trail.
session_idstringNoAuto-generated UUIDClient-supplied session identifier for grouping related evaluations.
phasestringNo"plan"Current PCW lifecycle phase. One of plan, commit, work. Affects the next_steps remediation guidance.
risk_baselinenumberNo0.0Current (pre-change) risk level. Must be finite.
risk_proposednumberNo0.0Projected risk level after the change. Must be finite.
risk_scorenumberNo--Alias for risk_proposed. Used only when risk_proposed is not provided.
profit_baselinenumberNo0.0Current (pre-change) profit metric. Must be finite.
profit_proposednumberNo0.0Projected profit metric after the change. Must be finite.
novelty_scorenumberNo0.5Novelty score (0-1). Higher values indicate more novel proposals. Must be finite.
complexity_scorenumberNo0.5Complexity score (0-1). Must exceed the complexity floor to pass the gate. Must be finite.
quality_scorenumberNo0.7Aggregate quality score (0-1). Must be finite.
quality_subscoresarray of numbersNo[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_approvalbooleanNofalseForce human-approval escalation even when all gates pass. Must be a boolean (non-boolean types are rejected).
time_sensitivebooleanNofalseFlag indicating a time-sensitive proposal. Must be a boolean.
reversiblebooleanNotrueWhether the proposed change can be rolled back. Irreversible changes always require human approval. Must be a boolean.
metadataobjectNo{}Arbitrary key-value pairs attached to the audit trail. Must be a JSON object.
shadow_modebooleanNofalseWhen 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_typestringNo"feature"Type of change: feature, refactor, bugfix, config. Non-feature types skip novelty and profit gates.
drift_baseline_dataarray of numbersNo--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

FieldTypeAlways presentDescription
statusstringYesGovernance outcome: proceed, pause, halt, or escalate.
confidencenumber or nullYesMinimum confidence across all gates (0-1). null if non-finite.
gates_passedintegerYesNumber of gates that passed.
gates_failedintegerYesNumber of gates that failed.
failing_gatesarray of stringsYesNames of the gates that failed. Possible values: risk, profit, novelty, complexity, quality, utility.
rationalestringYesHuman-readable explanation of the decision.
next_stepsarray of stringsYesRecommended actions based on decision status and current phase.
constraintsarray of stringsYesActive constraints (e.g., complexity floor not met, drift warnings).
decision_idstring (UUID)YesUnique identifier for this decision. Use this for audit trail lookups.
timestampstring (ISO 8601)YesUTC timestamp of the decision.
override_eligiblebooleanYesWhether the decision may be overridden with two-key approval. Always false when the complexity floor fails or critical drift is detected.
override_requiresarray of stringsYesRoles required to approve an override (e.g., risk_lead, security_lead). Empty when override_eligible is false.
gatesobjectWhen gates evaluatedPer-gate evaluation details. Each key is a gate name; see Gate Detail below.
driftobjectWhen drift detectedDrift policy enforcement result. See Drift Detail below.
shadow_resultobjectWhen shadow_mode is trueShadow mode evaluation metadata. See Shadow Detail below.
_tenant_idstringYesCustomer identifier derived from the API key (anonymous if unauthenticated).
_customer_idstringWhen authenticatedCustomer identifier (format: cust_...). Same value as _tenant_id for Unkey-authenticated requests.
_tierstringWhen authenticatedCustomer tier: community, professional, enterprise, or financial_services.
_request_idstringYesUnique request identifier for correlation.

Gate Detail

Each entry in the gates object has the following shape:

FieldTypeDescription
passedbooleanWhether this gate passed.
valuenumber or nullComputed gate value (rounded to 6 decimal places). null if non-finite.
thresholdnumber or nullThreshold used for the gate decision. null if non-finite.
confidencenumber or nullBayesian confidence score. Present for risk and profit gates; null for other gates.
messagestring or nullOptional diagnostic message.

The six gates are:

GateWhat it measures
riskBayesian posterior P(delta-risk >= 2 | data) against 0.95 threshold
profitBayesian posterior P(delta-profit >= 2 | data) against 0.95 threshold
noveltyLogistic function G(N) for novelty assessment
complexityHard floor -- proposal must meet minimum complexity score
qualityAggregate quality score against threshold
utilityLower confidence bound (LCB) of expected utility against threshold

Drift Detail

Present only when drift policy enforcement detects non-normal drift:

FieldTypeDescription
statusstringDrift severity: normal, warning, or critical.
kl_divergencenumber or nullKL divergence between current observations and baseline.
actionstringRecommended action: continue, alert_and_continue, or halt_and_recalibrate.
messagestring or nullDiagnostic message.

Critical drift upgrades the decision to halt and sets override_eligible to false.

Shadow Detail

Present only when shadow_mode is true:

FieldTypeDescription
shadow_onlybooleanAlways true in shadow mode.
observation_valuesarray of numbersComputed deltas [risk_proposed - risk_baseline, profit_proposed - profit_baseline].
baseline_hashstring or nullSHA-256 hash of the drift baseline (for auditability).
driftobject or nullDrift evaluation result (same shape as Drift Detail).

Decision Status Logic

The status is determined by the following priority rules:

  1. All gates pass and no human approval required -- proceed
  2. All gates pass but high/critical impact -- escalate
  3. All gates pass but human approval required -- pause
  4. Complexity floor fails -- halt (non-overridable)
  5. Critical drift detected -- halt (non-overridable)
  6. Gates fail with high/critical impact -- escalate
  7. Gates fail with human approval required -- pause
  8. 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.tool

POST /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

FieldTypeRequiredDefaultDescription
risk_scorenumberYes--Estimated risk score to evaluate. Must be finite. Must not be a boolean.
thresholdnumberNo0.5Risk threshold. The action is safe when risk_score < threshold. Must be finite. Must not be a boolean.
agent_idstringNo"api-caller"Identifier of the calling agent.
action_descriptionstringNo"Lambda risk check"Brief description of the action being checked.

Response Fields

FieldTypeAlways presentDescription
safebooleanYestrue when risk_score < threshold.
risk_scorenumberYesThe evaluated risk score (echoed back).
thresholdnumberYesThe threshold used (echoed back).
agent_idstringYesThe agent ID used (echoed back).
_tenant_idstringYesCustomer identifier derived from the API key (anonymous if unauthenticated).
_customer_idstringWhen authenticatedCustomer identifier (format: cust_...). Same value as _tenant_id for Unkey-authenticated requests.
_tierstringWhen authenticatedCustomer tier: community, professional, enterprise, or financial_services.
_request_idstringYesUnique 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.tool

Response:

{
  "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

FieldTypeDescription
statusstringok when all subsystems are healthy; degraded otherwise.
versionstringAEGIS package version.
stagestringDeployment stage (dev, staging, prod, or unknown).
checksobjectPer-subsystem health status.
checks.config.okbooleantrue if configuration loads successfully.
checks.gates.okbooleantrue if the gate evaluator initializes and runs a test evaluation.

HTTP Status Codes

CodeMeaning
200All subsystems healthy.
503One or more subsystems degraded.

Example

curl -s https://aegis-api-980022636831.us-central1.run.app/health \
  | python3 -m json.tool

Customer 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)

ParameterTypeRequiredDefaultDescription
monthstringNoCurrent monthFilter by month in YYYY-MM format.
limitintegerNo50Maximum number of decisions to return (max 200).

Response Fields

FieldTypeAlways presentDescription
decisionsarrayYesArray of decision summary objects.
decisions[].decision_idstring (UUID)YesUnique decision identifier.
decisions[].statusstringYesGovernance outcome: proceed, pause, halt, escalate.
decisions[].confidencenumber or nullYesMinimum confidence across all gates.
decisions[].proposal_summarystringYesBrief description of the proposal.
decisions[].timestampstring (ISO 8601)YesUTC timestamp of the decision.
decisions[].gates_passedintegerYesNumber of gates that passed.
decisions[].gates_failedintegerYesNumber of gates that failed.
totalintegerYesTotal decisions matching the filter.
monthstringYesThe YYYY-MM filter applied.
_customer_idstringYesCustomer identifier.
_request_idstringYesUnique 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.tool

GET /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

ParameterTypeRequiredDescription
decision_idstring (UUID)YesThe unique decision identifier.

Request Parameters (Query String)

ParameterTypeRequiredDefaultDescription
monthstringNoCurrent monthYYYY-MM of the decision (improves lookup performance).

Response Fields

FieldTypeAlways presentDescription
decision_idstring (UUID)YesUnique decision identifier.
statusstringYesGovernance outcome: proceed, pause, halt, escalate.
confidencenumber or nullYesMinimum confidence across all gates.
proposal_summarystringYesBrief description of the proposal.
estimated_impactstringYesImpact level.
timestampstring (ISO 8601)YesUTC timestamp.
rationalestringYesHuman-readable explanation of the decision.
next_stepsarray of stringsYesRecommended actions.
gatesobjectYesPer-gate evaluation details.
constraintsarray of stringsYesActive constraints.
override_eligiblebooleanYesWhether override is possible.
override_requiresarray of stringsYesRoles needed for override.
audit_hashstringYesSHA-256 hash of the decision record.
input_contextobjectYesOriginal input parameters.
_customer_idstringYesCustomer identifier.
_request_idstringYesUnique 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.tool

GET /customer/decisions/export

Export governance decisions as JSON or CSV. Useful for compliance reporting and audit trail extraction.

Request Parameters (Query String)

ParameterTypeRequiredDefaultDescription
formatstringNo"json"Export format: json or csv.
monthstringNoCurrent monthFilter by month in YYYY-MM format.

Response

  • JSON format (format=json): Returns Content-Type: application/json with the same structure as GET /customer/decisions.
  • CSV format (format=csv): Returns Content-Type: text/csv with 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.csv

Error Codes

All error responses have a consistent JSON shape:

{
  "error": "Human-readable error message"
}
HTTP CodeMeaningCommon causes
400Bad RequestInvalid 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.
403ForbiddenMissing or invalid Authorization: Bearer token.
404Not FoundUnknown path or wrong HTTP method (e.g., GET /evaluate).
429Too Many RequestsRate limit exceeded.
500Internal Server ErrorConfiguration error, evaluation engine failure.
503Service UnavailableOne 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, and null are rejected with HTTP 400.
  • Numeric fields must be finite (Inf, -Inf, and NaN are rejected). Boolean values in numeric fields are also rejected (Python isinstance(True, int) is True, so the API guards against this explicitly).
  • risk_score in /risk-check is required. All other numeric fields in /evaluate are optional with defaults.
  • quality_subscores must be a JSON array when present. Each element must be a finite number or null (booleans are rejected).
  • metadata must be a JSON object (not an array, string, or number).
  • drift_baseline_data elements must be finite numbers (booleans are rejected, null elements are filtered out).
  • estimated_impact must be a string when present. Non-string types are rejected.

See Also

On this page