REST API
Manage agents, policies, and alerts programmatically. All endpoints require an API key with appropriate permissions.
Authentication
Pass your API key in the X-Rune-Key header:
curl https://your-convex.convex.site/v1/agents \
-H "X-Rune-Key: rune_live_xxx"API keys are created in Settings > API Keys in the dashboard. Keys can have scoped permissions (agents:write, alerts:write). Keys with no permissions set have full access (legacy behavior).
Base URL
All API routes are served from your Convex HTTP endpoint:
https://<your-deployment>.convex.siteEvents
POST /v1/events
Ingest security events from the SDK. This is the primary ingestion endpoint used by Shield to send scan results and policy evaluations to the cloud.
curl -X POST https://events.runesec.dev/v1/events \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"event_id": "evt_abc123",
"timestamp": "2025-01-15T10:30:00Z",
"agent_id": "my-agent",
"event_type": "tool_call",
"direction": "outbound",
"scan_result": {
"risk_score": 0.95,
"l1_result": "block",
"threats_detected": [{"type": "prompt_injection"}]
}
}
]
}'{
"accepted": 1
}The SDK batches events automatically ( event_batch_size default: 50, event_flush_interval_seconds default: 5s). You do not need to call this endpoint directly.
Agents
GET /v1/agents
List all registered agents for your organization.
curl https://your-convex.convex.site/v1/agents \
-H "X-Rune-Key: rune_live_xxx"{
"agents": [
{
"_id": "abc123",
"agentId": "research-agent",
"name": "Research Agent",
"framework": "langchain",
"status": "active",
"tags": ["prod", "research"],
"riskScore": 0.12,
"eventCount": 1523,
"blockCount": 3,
"lastSeen": 1708905600000
}
]
}POST /v1/agents
Register a new agent. Requires agents:write permission.
curl -X POST https://your-convex.convex.site/v1/agents \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"agentId": "support-agent",
"name": "Customer Support Agent",
"framework": "openai",
"tags": ["prod", "support"]
}'{
"id": "def456",
"agentId": "support-agent"
}Policies
GET /v1/policies
List all active policies for your organization.
curl https://your-convex.convex.site/v1/policies \
-H "X-Rune-Key: rune_live_xxx"{
"policies": [
{
"_id": "pol123",
"name": "block-prompt-injection",
"version": 2,
"active": true,
"updatedAt": 1708905600000
}
]
}POST /v1/policies
Create a new policy. Requires policies:write permission. The YAML is validated and compiled before storage.
curl -X POST https://your-convex.convex.site/v1/policies \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Security Policy",
"yamlContent": "version: \"1.0\"\nrules:\n - name: block-injection\n scanner: prompt_injection\n action: block\n severity: critical"
}'{
"id": "pol789",
"name": "Production Security Policy"
}POST /v1/policies/update
Update a policy's name or YAML content. Requires policies:write permission. Updating YAML bumps the version number and recompiles.
curl -X POST https://your-convex.convex.site/v1/policies/update \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"policyId": "pol789",
"name": "Updated Policy Name",
"yamlContent": "version: \"1.0\"\nrules: ..."
}'{"updated": true}POST /v1/policies/toggle
Enable or disable a policy. Requires policies:write permission.
curl -X POST https://your-convex.convex.site/v1/policies/toggle \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{"policyId": "pol789", "active": false}'{"updated": true}POST /v1/policies/delete
Permanently delete a policy. Requires policies:write permission.
curl -X POST https://your-convex.convex.site/v1/policies/delete \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{"policyId": "pol789"}'{"deleted": true}POST /v1/policies/validate
Validate a policy YAML string without persisting it. Useful for CI/CD pipelines and editor integrations. Any valid API key can call this.
curl -X POST https://your-convex.convex.site/v1/policies/validate \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{"yamlContent": "version: \"1.0\"\nrules:\n - name: test\n scanner: prompt_injection\n action: block\n severity: critical"}'{
"valid": true,
"compiled": { "rules": [...] },
"error": null
}Alerts
GET /v1/alerts
List all open alerts for your organization.
curl https://your-convex.convex.site/v1/alerts \
-H "X-Rune-Key: rune_live_xxx"{
"alerts": [
{
"_id": "alrt789",
"severity": "critical",
"alertType": "injection_detected",
"title": "Prompt injection detected on research-agent",
"status": "open",
"agentId": "research-agent",
"occurrences": 3
}
]
}POST /v1/alerts/update
Update an alert status. Requires alerts:write permission.
curl -X POST https://your-convex.convex.site/v1/alerts/update \
-H "X-Rune-Key: rune_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"alertId": "alrt789",
"status": "resolved",
"note": "False alarm — test data"
}'Valid statuses: open, investigating, resolved, false_positive.
Setting status to false_positive automatically creates a false-positive pattern that feeds back to the SDK scanners as an allowlist entry.
Health Check
GET /health
No authentication required.
curl https://your-convex.convex.site/health{
"status": "ok",
"timestamp": 1708905600000
}Error Responses
| Status | Meaning |
|---|---|
| 401 | Invalid or missing API key |
| 403 | API key lacks required permission |
| 400 | Invalid request body or missing required fields |
| 404 | Resource not found |
All error responses return JSON with an error field:
{"error": "Invalid or missing API key"}Rate Limits
API endpoints are rate-limited per organization:
| Endpoint Type | Limit |
|---|---|
| Read endpoints (GET) | 100 requests/minute |
| Write endpoints (POST) | 30 requests/minute |
| Event ingestion (POST /v1/events) | 1,000 events/second |
Rate-limited responses return 429 Too Many Requests with a Retry-After header.
Pagination
List endpoints support cursor-based pagination via cursor and limit query parameters:
curl "https://your-convex.convex.site/v1/alerts?limit=50&cursor=abc123" \
-H "X-Rune-Key: rune_live_xxx"Responses include a next_cursor field when more results are available. Omit cursor to start from the beginning. Default limit is 50, maximum is 200.
OpenAPI Spec
A machine-readable OpenAPI 3.1 specification is available for all v1 endpoints. Use it to generate client libraries or import into tools like Postman:
https://runesec.dev/openapi.yamlMCP Server
All API endpoints are also available as MCP tools via the Rune MCP server. This lets Claude Code, Cursor, and Windsurf manage your security policies and triage alerts natively.
pip install "runesec[mcp]"
rune-mcp # starts MCP server on stdioSee the MCP documentation for setup instructions and the full list of available tools.
Permissions
API keys can be scoped with fine-grained permissions. Keys with no permissions set have full access (legacy behavior).
| Permission | Grants Access To |
|---|---|
| agents:write | POST /v1/agents |
| policies:write | POST /v1/policies, /v1/policies/update, /toggle, /delete |
| alerts:write | POST /v1/alerts/update |
All read endpoints (GET) are accessible with any valid API key regardless of permissions.