Skip to content

API Endpoints Reference

Complete reference for the SCP REST API.

Base URL: http://localhost:8000 (development)

Interactive Documentation: Visit /docs (Swagger UI) or /redoc (ReDoc)


Authentication

Agent Authentication (v0.3)

Agents authenticate using API keys in the X-API-Key header:

X-API-Key: sk_your_api_key_here

API keys are generated when registering agents (see Agent Registry API).

Admin Authentication

Admin operations (bundle registry, agent registry, audit admin reads) require an X-Admin-Key header:

X-Admin-Key: admin_your_key_here

The admin key is set via ADMIN_API_KEY in the deployment environment. Requests without a valid key return 401. Requests to a deployment where the key is not configured return 503.

See Security Overview for key generation and storage guidance.


Context API (v0.3)

The primary API for agents to request governed context.

Request Context

POST /api/context
Content-Type: application/json
X-API-Key: sk_your_api_key_here

{
  "task_type": "prior_auth_check",
  "params": {
    "drug": "Keytruda",
    "diagnosis": "lung cancer"
  }
}

Response: 200 OK

{
  "success": true,
  "request_id": "ctx_abc123def456",
  "agent_id": "agent:prior-auth-prod",
  "role_id": "role:prior-auth-agent",
  "task_type": "prior_auth_check",
  "scd_ids": [
    "scd:standards:hipaa-privacy-rule",
    "scd:project:clinical-guidelines-v1.2",
    "scd:project:formulary-2024"
  ],
  "scd_content": {
    "scd:standards:hipaa-privacy-rule": { ... },
    "scd:project:clinical-guidelines-v1.2": { ... }
  },
  "timestamp": 1706288400,
  "processing_time_ms": 34
}

Error Responses:

401 Unauthorized - Invalid or missing API key

{
  "success": false,
  "error_code": "AUTH_FAILED",
  "error_message": "Invalid or expired API key"
}

403 Forbidden - Task type not allowed for this agent

{
  "success": false,
  "error_code": "INTENT_NOT_ALLOWED",
  "error_message": "Task type 'claims_adjudication' not in agent's allowed intents"
}


Context Health Check

GET /api/context/health

Response: 200 OK

{
  "status": "healthy",
  "service": "control-plane-api",
  "version": "1.0.0"
}


Agent Registry API

Register Agent

POST /api/agents
Content-Type: application/json

{
  "agent_id": "agent:prior-auth-prod",
  "name": "Prior Auth Production Agent",
  "role_id": "role:prior-auth-agent",
  "allowed_intents": [
    "prior_auth_check",
    "formulary_lookup",
    "clinical_guidelines_check"
  ],
  "status": "active"
}

Response: 201 Created

{
  "agent_id": "agent:prior-auth-prod",
  "name": "Prior Auth Production Agent",
  "role_id": "role:prior-auth-agent",
  "allowed_intents": ["prior_auth_check", "formulary_lookup", "clinical_guidelines_check"],
  "status": "active",
  "created_at": "2026-01-26T10:00:00Z"
}


List Agents

GET /api/agents?role_id=role:prior-auth-agent&status=active

Query Parameters: - role_id - Filter by role - status - Filter by status (active, inactive, suspended) - limit - Max results (default: 100) - offset - Pagination offset

Response: 200 OK

{
  "agents": [
    {
      "agent_id": "agent:prior-auth-prod",
      "name": "Prior Auth Production Agent",
      "role_id": "role:prior-auth-agent",
      "status": "active",
      "created_at": "2026-01-26T10:00:00Z"
    }
  ],
  "total": 1
}


Get Agent

GET /api/agents/{agent_id}

Response: 200 OK

{
  "agent_id": "agent:prior-auth-prod",
  "name": "Prior Auth Production Agent",
  "role_id": "role:prior-auth-agent",
  "allowed_intents": ["prior_auth_check", "formulary_lookup"],
  "status": "active",
  "created_at": "2026-01-26T10:00:00Z",
  "api_keys": [
    {
      "key_id": "key_prod_default",
      "created_at": "2026-01-26T10:00:00Z",
      "last_used_at": "2026-01-26T15:30:00Z"
    }
  ]
}


Update Agent

PUT /api/agents/{agent_id}
Content-Type: application/json

{
  "name": "Updated Agent Name",
  "allowed_intents": ["prior_auth_check", "formulary_lookup", "new_intent"],
  "status": "active"
}

Response: 200 OK


Generate API Key

POST /api/agents/{agent_id}/api-keys
Content-Type: application/json

{
  "key_id": "key_prod_v2"
}

Response: 201 Created

{
  "key_id": "key_prod_v2",
  "api_key": "sk_abc123def456...",
  "agent_id": "agent:prior-auth-prod",
  "created_at": "2026-01-26T10:00:00Z"
}

Important: The api_key is only returned once. Store it securely.


Revoke API Key

DELETE /api/agents/{agent_id}/api-keys/{key_id}

Response: 204 No Content


Add Policy Override

Add SCD overrides or restrictions for a specific agent.

POST /api/agents/{agent_id}/policy
Content-Type: application/json

{
  "overrides": ["scd:project:special-guidelines"],
  "restrictions": ["scd:project:phi-handling"]
}

Response: 200 OK


Bundle Registry API

Create/Publish Bundle

POST /api/bundles
Content-Type: application/json

{
  "id": "bundle:my-bundle",
  "type": "concern",
  "version": "1.0.0",
  "title": "My Bundle",
  "description": "Bundle description",
  "scds": ["scd:project:my-scd"],
  "imports": [],
  "provenance": {
    "created_by": "user@example.com",
    "created_at": "2026-01-26T10:00:00Z",
    "rationale": "Initial bundle creation"
  }
}

Response: 201 Created

{
  "bundle_id": "bundle:my-bundle",
  "version": "1.0.0",
  "status": "published"
}


List Bundles

GET /api/bundles?type=concern&limit=100

Query Parameters: - type - Filter by bundle type (meta, standards, domain, concern, project) - limit - Max results (default: 100) - offset - Pagination offset

Response: 200 OK

{
  "bundles": [
    {
      "id": "bundle:my-bundle",
      "version": "1.0.0",
      "type": "concern",
      "title": "My Bundle",
      "created_at": "2026-01-26T10:00:00Z"
    }
  ],
  "total": 1
}


Get Bundle Version

GET /api/bundles/{bundle_id}/versions/{version}

Response: 200 OK

{
  "id": "bundle:acme-security",
  "type": "concern",
  "version": "1.0.0",
  "title": "Acme Security Controls",
  "description": "Security standards for Acme Health Corp",
  "scds": ["scd:project:security-controls"],
  "imports": [],
  "manifest": { ... }
}


Deactivate Bundle

DELETE /api/bundles/{bundle_id}/versions/{version}

Response: 204 No Content


Tag Management API

Tags are mutable pointers to immutable bundles.

Create Tag

POST /api/tags
Content-Type: application/json

{
  "tag": "prior-auth:latest",
  "bundle_id": "bundle:prior-auth",
  "bundle_version": "1.0.0"
}

Response: 201 Created

{
  "tag": "prior-auth:latest",
  "bundle_id": "bundle:prior-auth",
  "bundle_version": "1.0.0",
  "created_at": "2026-01-26T10:00:00Z"
}


Update Tag

Move a tag to point to a different bundle version (zero-downtime update).

PUT /api/tags/{tag}
Content-Type: application/json

{
  "bundle_id": "bundle:prior-auth",
  "bundle_version": "1.1.0"
}

Response: 200 OK

{
  "tag": "prior-auth:latest",
  "bundle_id": "bundle:prior-auth",
  "bundle_version": "1.1.0",
  "updated_at": "2026-01-26T12:00:00Z"
}


Resolve Tag

GET /api/tags/{tag}

Response: 200 OK

{
  "tag": "prior-auth:latest",
  "bundle_id": "bundle:prior-auth",
  "bundle_version": "1.1.0",
  "resolved_bundle_ids": [
    "bundle:prior-auth:1.1.0",
    "bundle:acme-health-corp:1.0.0",
    "bundle:hipaa:1.0.0"
  ],
  "context_yaml": "..."
}


Deployment API

Deploy Bundle

POST /api/deploy
Content-Type: application/json

{
  "project_bundles": [
    {
      "id": "bundle:prior-auth",
      "version": "1.0.0"
    }
  ],
  "deployment_id": "prod-2026-01-26"
}

Response: 201 Created

{
  "deployment_id": "prod-2026-01-26",
  "project_bundles": ["bundle:prior-auth:1.0.0"],
  "resolved_bundles": [
    "bundle:meta:1.0.0",
    "bundle:hipaa:1.0.0",
    "bundle:acme-health-corp:1.0.0",
    "bundle:prior-auth:1.0.0"
  ],
  "status": "active",
  "created_at": "2026-01-26T14:00:00Z"
}


Get Deployment

GET /api/deployments/{deployment_id}

Response: 200 OK


List Deployments

GET /api/deployments?status=active

Response: 200 OK


Audit API

Verify Audit Chain Integrity

Walks the entire hash-chained audit log and recomputes every record hash.

GET /api/audit/verify
X-API-Key: sk_your_api_key_here

Response: 200 OK

{
  "status": "ok",
  "record_count": 1042,
  "legacy_record_count": 0,
  "first_chained_sequence": 1,
  "last_verified_at": "2026-04-19T10:30:00Z",
  "tampered_at_sequence": null,
  "error": null
}

If tampering is detected:

{
  "status": "tampered",
  "record_count": 1042,
  "legacy_record_count": 0,
  "first_chained_sequence": 1,
  "last_verified_at": "2026-04-19T10:30:00Z",
  "tampered_at_sequence": 214,
  "error": null
}

Authentication: Admin API key required (X-API-Key header).


Telemetry API

Telemetry endpoints are served on port 8004 (not 8000).

Get Telemetry Config

GET /config

Response: 200 OK

{
  "enabled": false,
  "endpoint": null,
  "deployment_id": "uuid-here",
  "daily_report_hour": 0,
  "retry_max_attempts": 5,
  "retry_backoff_base": 60
}


Get Telemetry Stats

GET /stats

Response: 200 OK

{
  "total_reports_sent": 12,
  "total_reports_failed": 0,
  "last_report_at": "2026-04-19T00:00:00Z",
  "queue_depth": 0
}


Get Telemetry Log

GET /log?limit=50&offset=0

Query Parameters: - limit — max entries to return (default: 50) - offset — pagination offset

Response: 200 OK

[
  {
    "id": 1,
    "reported_at": "2026-04-19T00:00:00Z",
    "status": "sent",
    "agent_count": 5,
    "context_request_count": 120,
    "bundle_count": 3
  }
]


Trigger Manual Report

POST /trigger

Forces an immediate telemetry report outside the daily schedule.

Response: 200 OK

{
  "status": "triggered"
}


Rules Engine API

Create Rule Schema

POST /api/rules/schemas
Content-Type: application/json

{
  "id": "schema:formulary",
  "schema": {
    "type": "object",
    "properties": {
      "drug_name": {"type": "string"},
      "tier": {"type": "integer"},
      "requires_pa": {"type": "boolean"}
    },
    "required": ["drug_name", "tier"]
  }
}

Response: 201 Created


Create Rule Set

POST /api/rules/rule-sets
Content-Type: application/json

{
  "id": "ruleset:formulary:acme",
  "version": "2026-Q1",
  "schema_id": "schema:formulary"
}

Response: 201 Created


Add Rule to Rule Set

POST /api/rules/rule-sets/{rule_set_id}/rules
Content-Type: application/json

{
  "rule_id": "rule:lisinopril",
  "rule_data": {
    "drug_name": "Lisinopril",
    "tier": 1,
    "requires_pa": false
  }
}

Response: 201 Created


List Rule Sets

GET /api/rules/rule-sets

Response: 200 OK


Error Responses

400 Bad Request

{
  "error": "validation_error",
  "message": "Invalid bundle type",
  "details": { ... }
}

401 Unauthorized

{
  "error": "auth_failed",
  "message": "Invalid or missing API key"
}

403 Forbidden

{
  "error": "intent_not_allowed",
  "message": "Task type not in agent's allowed intents"
}

404 Not Found

{
  "error": "not_found",
  "message": "Agent not found: agent:xyz"
}

409 Conflict

{
  "error": "conflict",
  "message": "Bundle version already exists (immutable)"
}

500 Internal Server Error

{
  "error": "internal_error",
  "message": "An unexpected error occurred"
}

API Status

Endpoint Group Status Notes
Context API (v0.3) ✅ Implemented API key auth, intent validation, role-based context, optional full content
Agent Registry ✅ Implemented CRUD, API keys, revocation, lifecycle enforcement
Bundle Registry ✅ Implemented CRUD, versioning, import resolution
Tag Management ✅ Implemented Create, update, resolve tags
Deployment ✅ Implemented Deploy, list, get deployments
Rules Engine ✅ Implemented Schemas, rule sets, rules
Audit API ✅ Implemented Hash-chained audit log, chain integrity verification
Telemetry API ✅ Implemented Usage stats, log, manual trigger (port 8004)
Usage/Adherence 🚧 Partial Tables exist, analytics TBD

gRPC API

For streaming context, use the gRPC API on port 8002.

RequestContext (v0.3)

rpc RequestContext(ContextRequest) returns (ContextResponse);

message ContextRequest {
  string api_key = 1;
  string task_type = 2;
  map<string, string> params = 3;
}

message ContextResponse {
  bool success = 1;
  string request_id = 2;
  string agent_id = 3;
  string role_id = 4;
  string task_type = 5;
  repeated string scd_ids = 6;
  map<string, string> scd_content = 7;
  int64 timestamp = 8;
  int32 processing_time_ms = 9;
  string error_code = 10;
  string error_message = 11;
}

Subscribe (v0.2)

rpc Subscribe(SubscribeRequest) returns (stream ContextMessage);

message SubscribeRequest {
  string tag = 1;
  string agent_id = 2;
  string auth_token = 3;
}

Next Steps