# API Reference AgentPaaS exposes a RESTful API via FastAPI. All endpoints (except `/health` and `/`) require authentication via the `Authorization` header with a bearer API key. Base URL: `http://localhost:8000` (development) or your production domain. Interactive docs: `GET /docs` (Swagger UI) | `GET /redoc` (ReDoc) --- ## Authentication All authenticated endpoints require: ``` Authorization: Bearer ap_xxxxxxxxxxxx ``` API keys are scoped. Common scopes: `agents:read`, `agents:write`, `agents:execute`, `keys:*`, `billing:read`, `admin:*`. Rate limiting applies per API key (sliding window, 60 requests/minute default). Exceeding the limit returns `429 Too Many Requests` with a `Retry-After: 60` header. --- ## Agent CRUD ### POST /api/v1/agents Create a new agent. The config is validated by compiling it through `lambdagent.from_config()`. **Request:** ```json { "name": "my-research-agent", "description": "A research agent for summarization", "config": { "agentId": "research-01", "name": "researcher", "type": "react", "systemPrompt": "You are a research assistant.", "model": { "provider": "anthropic", "name": "claude-sonnet-4-20250514" }, "react": { "maxSteps": 10 } }, "tags": ["research", "production"], "environment": "production" } ``` **Response (201):** ```json { "agent_id": "ag_abc123", "version": 1, "created_at": "2026-04-05T12:00:00Z", "endpoint": "/api/v1/agents/ag_abc123" } ``` **Errors:** `400 INVALID_CONFIG` -- config failed compilation. --- ### GET /api/v1/agents List all active agents for the authenticated tenant. **Query Parameters:** | Param | Type | Description | |-------|------|-------------| | `tag` | string | Filter by tag (optional) | **Response (200):** ```json { "agents": [ { "id": "ag_abc123", "name": "my-research-agent", "description": "...", "current_version": 3, "tags": ["research"], "environment": "production", "status": "active", "created_at": "...", "updated_at": "..." } ], "count": 1 } ``` --- ### GET /api/v1/agents/{agent_id} Get agent details including current version config. **Response (200):** Full agent record with `config` field populated from the current version. **Errors:** `404 AGENT_NOT_FOUND` --- ### PUT /api/v1/agents/{agent_id} Update agent config. Automatically increments the version number. If the config hash is unchanged, no new version is created. **Required scope:** `agents:write` **Request:** ```json { "config": { "...updated config..." }, "changelog": "Increased maxSteps to 20" } ``` **Response (200):** ```json { "agent_id": "ag_abc123", "version": 4, "updated_at": "2026-04-05T12:30:00Z" } ``` **Errors:** `400 INVALID_CONFIG`, `404 AGENT_NOT_FOUND` --- ### DELETE /api/v1/agents/{agent_id} Soft delete an agent (sets status to `deleted`). **Required scope:** `agents:write` **Response (200):** ```json { "message": "Agent deleted", "agent_id": "ag_abc123" } ``` --- ## Execution ### POST /api/v1/agents/{agent_id}/run Synchronous agent execution. Compiles the config, runs the agent, and returns the result. **Required scope:** `agents:execute` **Headers:** | Header | Description | |--------|-------------| | `X-Idempotency-Key` | Optional. If provided, duplicate requests return the cached result. | **Request:** ```json { "input": "Summarize the latest advances in quantum computing", "parameters": { "model.temperature": 0.5, "react.maxSteps": 15 }, "context": {} } ``` The `parameters` field supports dot-notation for deep overrides (e.g., `model.temperature` sets `config.model.temperature`). **Response (200):** ```json { "run_id": "run_xyz789", "status": "completed", "output": "Quantum computing has seen...", "usage": { "input_tokens": 1234, "output_tokens": 567, "total_tokens": 1801, "steps": 5, "duration_ms": 8320 } } ``` **Errors:** `404 AGENT_NOT_FOUND`, `429 RATE_LIMITED`, `500 EXECUTION_ERROR` (with `run_id` for debugging) --- ### POST /api/v1/agents/{agent_id}/run/stream Server-Sent Events (SSE) streaming execution. Emits real-time step events as the agent runs. **Response:** `text/event-stream` **Event types:** | Event | Data | Description | |-------|------|-------------| | `think` | `{ "step": 1, "content": "...", "duration_ms": 500 }` | Agent reasoning step | | `think_chunk` | `{ "content": "partial text" }` | Streaming LLM chunk (ClaudeLam) | | `tool_call` | `{ "step": 2, "tool": "search", "content": "query" }` | Tool invocation | | `tool_result` | `{ "step": 2, "content": "result..." }` | Tool output | | `error` | `{ "message": "..." }` | Tool or execution error | | `answer` | `{ "content": "final answer" }` | Final agent answer | | `done` | `{ "status": "completed", "output": "...", "steps": 5 }` | Execution complete | **Example client (JavaScript):** ```javascript const es = new EventSource("/api/v1/agents/ag_abc123/run/stream", { method: "POST", headers: { "Authorization": "Bearer ap_xxx" }, body: JSON.stringify({ input: "Hello" }), }); es.addEventListener("think", (e) => console.log("Think:", JSON.parse(e.data))); es.addEventListener("done", (e) => { console.log("Done:", JSON.parse(e.data)); es.close(); }); ``` --- ### POST /api/v1/agents/{agent_id}/runs/record Record an externally-executed run (e.g., from Claude Code CLI). Does NOT trigger lambdagent execution. **Request:** ```json { "input": "...", "output": "...", "status": "completed", "duration_ms": 5000, "steps": 3, "source": "claude-code-cli" } ``` **Response (201):** ```json { "run_id": "run_abc", "status": "completed", "source": "claude-code-cli" } ``` --- ### GET /api/v1/agents/{agent_id}/runs List recent runs for an agent. **Query Parameters:** `limit` (default 20) **Response (200):** ```json { "runs": [ { "id": "run_xyz", "status": "completed", "duration_ms": 8320, "...": "..." } ] } ``` --- ## Versions ### GET /api/v1/agents/{agent_id}/versions List all versions of an agent, ordered newest first. **Required scope:** `agents:read` **Response (200):** ```json { "versions": [ { "agent_id": "ag_abc123", "version": 3, "config": "...", "config_hash": "sha256...", "changelog": "Increased maxSteps", "created_by": "usr_xxx", "created_at": "...", "is_current": true } ] } ``` --- ### POST /api/v1/agents/{agent_id}/rollback Rollback to a previous version. **Request:** ```json { "target_version": 2 } ``` **Response (200):** ```json { "agent_id": "ag_abc123", "version": 2, "message": "Rolled back" } ``` **Errors:** `404 VERSION_NOT_FOUND` --- ## Analysis Static analysis endpoints for agent configs. These do not require an agent to be registered -- they accept raw configs. ### POST /api/v1/analyze/lint Lint an agent config for structural defects (26 rules: L001-L026). **Request:** ```json { "config": { "type": "react", "systemPrompt": "...", "react": { "maxSteps": 50 } }, "framework": "auto" } ``` **Response (200):** ```json { "framework": "native", "errors": [ { "rule": "L004a", "level": "ERROR", "message": "No terminate tool found (Y combinator has no base case)" } ], "warnings": [ { "rule": "L010", "level": "WARN", "message": "maxSteps > 10; recommend runtime.engine: cek" } ], "info": [ { "rule": "L025", "level": "INFO", "message": "Detected framework: native lambdagent" } ] } ``` --- ### POST /api/v1/analyze/type-check Type-check an agent pipeline using the T-Compose rule. **Response (200):** ```json { "type_safe": true, "errors": [] } ``` Or when type errors are found: ```json { "type_safe": false, "errors": [ { "stage": 1, "output_type": "Int", "input_type": "Json({name: string})" } ] } ``` --- ### POST /api/v1/analyze/cost Estimate worst-case execution cost via graded types. **Response (200):** ```json { "tokens_upper_bound": 45000, "latency_sec": 12.5, "cost_usd": 0.135, "success_probability": 0.92 } ``` --- ### POST /api/v1/analyze/parallel-safety Check store independence for parallel agents (Paper II Proposition 30). **Response (200):** ```json { "safe": true, "conflicts": [] } ``` --- ### POST /api/v1/analyze/full Run all analysis passes (lint + type-check + cost + parallel-safety) in a single request. **Response (200):** ```json { "lint": { "framework": "...", "errors": [], "warnings": [], "info": [] }, "types": { "type_safe": true, "errors": [] }, "cost": { "tokens_upper_bound": 45000, "latency_sec": 12.5, "cost_usd": 0.135, "success_probability": 0.92 }, "parallel": { "safe": true, "conflicts": [] } } ``` --- ## API Keys (Auth) ### POST /api/v1/auth/keys Create a new API key for the current tenant. **Request:** ```json { "name": "production-key", "scopes": ["agents:read", "agents:execute"], "rate_limit": 120, "expires_at": "2027-01-01T00:00:00Z" } ``` **Response (201):** ```json { "key_id": "key_abc123", "api_key": "ap_a1b2c3d4e5f6...", "warning": "Store this key securely. It will not be shown again." } ``` --- ### GET /api/v1/auth/keys List all API keys for the current tenant (key values are not returned, only prefixes). **Response (200):** ```json { "keys": [ { "id": "key_abc123", "key_prefix": "ap_a1b2", "name": "production-key", "scopes": ["agents:read", "agents:execute"], "rate_limit": 120, "status": "active", "last_used_at": "...", "created_at": "..." } ] } ``` --- ### DELETE /api/v1/auth/keys/{key_id} Revoke an API key (sets status to `revoked`). **Response (200):** ```json { "message": "Key revoked" } ``` --- ## Admin All admin endpoints require the `admin:*` scope. ### POST /api/v1/admin/tenants Create a new tenant with an admin user and initial API key. **Request:** ```json { "name": "Acme Corp", "plan": "pro", "admin_email": "admin@acme.com" } ``` **Response (201):** ```json { "tenant_id": "tn_xyz", "user_id": "usr_abc", "api_key": "ap_...", "warning": "Store this API key securely." } ``` --- ### GET /api/v1/admin/tenants/{tenant_id} Get tenant details. **Errors:** `403 FORBIDDEN` (non-admin), `404 TENANT_NOT_FOUND` --- ### PUT /api/v1/admin/tenants/{tenant_id}/quota Set tenant resource quotas. **Request:** ```json { "tokens_monthly": 5000000, "concurrency": 20, "agents": 100 } ``` **Response (200):** ```json { "message": "Quota updated" } ``` --- ### GET /api/v1/admin/tenants/{tenant_id}/usage Get tenant usage statistics. **Response (200):** ```json { "runs": 1234, "input_tokens": 5678900, "output_tokens": 2345600, "total_duration_ms": 98765432 } ``` --- ## Billing ### GET /api/v1/billing/usage Query usage data for the current tenant. **Query Parameters:** | Param | Type | Description | |-------|------|-------------| | `group_by` | string | `agent` (default), `model`, or `day` | **Response (200):** ```json { "usage": [ { "agent_id": "ag_abc123", "runs": 42, "input_tokens": 123456, "output_tokens": 65432, "total_ms": 345000 } ], "tenant_id": "tn_xyz" } ``` --- ## Status ### GET /api/v1/status Platform-wide status overview: total agents, runs, success rate, average latency. ### GET /api/v1/status/agents All agents status summary. ### GET /api/v1/status/agents/{agent_id} Detailed status for a single agent. ### GET /api/v1/status/agents/{agent_id}/health Agent health score. --- ## Metrics ### GET /api/v1/metrics/overview Platform metrics snapshot for monitoring dashboards. --- ## Health ### GET /health Unauthenticated health check endpoint. **Response (200):** ```json { "status": "ok", "version": "0.1.0" } ``` --- ### GET / Root endpoint with service information. **Response (200):** ```json { "service": "AgentPaaS", "version": "0.1.0", "docs": "/docs", "description": "Agent Platform as a Service -- Every agent is a Lambda term." } ``` --- ## Common Error Format All errors follow a consistent structure: ```json { "error": { "code": "ERROR_CODE", "message": "Human-readable description" } } ``` | HTTP Status | Code | Description | |-------------|------|-------------| | 400 | `INVALID_CONFIG` | Agent config failed compilation | | 401 | `UNAUTHORIZED` | Missing or invalid API key | | 403 | `FORBIDDEN` | Insufficient scope for this operation | | 404 | `AGENT_NOT_FOUND` | Agent does not exist or is deleted | | 404 | `VERSION_NOT_FOUND` | Requested version does not exist | | 404 | `JOB_NOT_FOUND` | Async job not found | | 421 | `HTTPS_REQUIRED` | HTTPS required in production | | 429 | `RATE_LIMITED` | Rate limit exceeded | | 500 | `EXECUTION_ERROR` | Agent execution failed (includes `run_id`) | --- ## Security Headers All responses include: - `X-Content-Type-Options: nosniff` - `X-Frame-Options: DENY` - `X-XSS-Protection: 1; mode=block` - `Referrer-Policy: strict-origin-when-cross-origin` - `X-Response-Time-Ms: ` - `X-Request-ID: ` (for log correlation) Production-only: - `Strict-Transport-Security: max-age=31536000; includeSubDomains` - `Content-Security-Policy: default-src 'self'` --- ## Jobs (Async Execution) ### GET /api/v1/jobs/{job_id} Get async job status and result. **Response (200):** ```json { "job_id": "job_abc", "status": "completed", "result": "...", "created_at": "..." } ``` Status values: `pending`, `running`, `completed`, `failed`, `cancelled`. --- ### POST /api/v1/jobs/{job_id}/cancel Cancel a running or pending async job. **Response (200):** ```json { "message": "Job cancelled", "job_id": "job_abc" } ```