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_keyis 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¶
- See CLI Commands for bundle authoring
- See Architecture Overview for system design
- See Getting Started for quick start