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)
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.
Create a new agent. The config is validated by compiling it through lambdagent.from_config().
Request:
{
"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):
{
"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.
List all active agents for the authenticated tenant.
Query Parameters:
| Param | Type | Description |
|---|---|---|
tag |
string | Filter by tag (optional) |
Response (200):
{
"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 agent details including current version config.
Response (200): Full agent record with config field populated from the current version.
Errors: 404 AGENT_NOT_FOUND
Update agent config. Automatically increments the version number. If the config hash is unchanged, no new version is created.
Required scope: agents:write
Request:
{
"config": { "...updated config..." },
"changelog": "Increased maxSteps to 20"
}
Response (200):
{
"agent_id": "ag_abc123",
"version": 4,
"updated_at": "2026-04-05T12:30:00Z"
}
Errors: 400 INVALID_CONFIG, 404 AGENT_NOT_FOUND
Soft delete an agent (sets status to deleted).
Required scope: agents:write
Response (200):
{ "message": "Agent deleted", "agent_id": "ag_abc123" }
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:
{
"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):
{
"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)
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):
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(); });
Record an externally-executed run (e.g., from Claude Code CLI). Does NOT trigger lambdagent execution.
Request:
{
"input": "...",
"output": "...",
"status": "completed",
"duration_ms": 5000,
"steps": 3,
"source": "claude-code-cli"
}
Response (201):
{ "run_id": "run_abc", "status": "completed", "source": "claude-code-cli" }
List recent runs for an agent.
Query Parameters: limit (default 20)
Response (200):
{ "runs": [ { "id": "run_xyz", "status": "completed", "duration_ms": 8320, "...": "..." } ] }
List all versions of an agent, ordered newest first.
Required scope: agents:read
Response (200):
{
"versions": [
{
"agent_id": "ag_abc123",
"version": 3,
"config": "...",
"config_hash": "sha256...",
"changelog": "Increased maxSteps",
"created_by": "usr_xxx",
"created_at": "...",
"is_current": true
}
]
}
Rollback to a previous version.
Request:
{ "target_version": 2 }
Response (200):
{ "agent_id": "ag_abc123", "version": 2, "message": "Rolled back" }
Errors: 404 VERSION_NOT_FOUND
Static analysis endpoints for agent configs. These do not require an agent to be registered -- they accept raw configs.
Lint an agent config for structural defects (26 rules: L001-L026).
Request:
{
"config": { "type": "react", "systemPrompt": "...", "react": { "maxSteps": 50 } },
"framework": "auto"
}
Response (200):
{
"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" }
]
}
Type-check an agent pipeline using the T-Compose rule.
Response (200):
{
"type_safe": true,
"errors": []
}
Or when type errors are found:
{
"type_safe": false,
"errors": [
{ "stage": 1, "output_type": "Int", "input_type": "Json({name: string})" }
]
}
Estimate worst-case execution cost via graded types.
Response (200):
{
"tokens_upper_bound": 45000,
"latency_sec": 12.5,
"cost_usd": 0.135,
"success_probability": 0.92
}
Check store independence for parallel agents (Paper II Proposition 30).
Response (200):
{
"safe": true,
"conflicts": []
}
Run all analysis passes (lint + type-check + cost + parallel-safety) in a single request.
Response (200):
{
"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": [] }
}
Create a new API key for the current tenant.
Request:
{
"name": "production-key",
"scopes": ["agents:read", "agents:execute"],
"rate_limit": 120,
"expires_at": "2027-01-01T00:00:00Z"
}
Response (201):
{
"key_id": "key_abc123",
"api_key": "ap_a1b2c3d4e5f6...",
"warning": "Store this key securely. It will not be shown again."
}
List all API keys for the current tenant (key values are not returned, only prefixes).
Response (200):
{
"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": "..."
}
]
}
Revoke an API key (sets status to revoked).
Response (200):
{ "message": "Key revoked" }
All admin endpoints require the admin:* scope.
Create a new tenant with an admin user and initial API key.
Request:
{
"name": "Acme Corp",
"plan": "pro",
"admin_email": "admin@acme.com"
}
Response (201):
{
"tenant_id": "tn_xyz",
"user_id": "usr_abc",
"api_key": "ap_...",
"warning": "Store this API key securely."
}
Get tenant details.
Errors: 403 FORBIDDEN (non-admin), 404 TENANT_NOT_FOUND
Set tenant resource quotas.
Request:
{
"tokens_monthly": 5000000,
"concurrency": 20,
"agents": 100
}
Response (200):
{ "message": "Quota updated" }
Get tenant usage statistics.
Response (200):
{
"runs": 1234,
"input_tokens": 5678900,
"output_tokens": 2345600,
"total_duration_ms": 98765432
}
Query usage data for the current tenant.
Query Parameters:
| Param | Type | Description |
|---|---|---|
group_by |
string | agent (default), model, or day |
Response (200):
{
"usage": [
{
"agent_id": "ag_abc123",
"runs": 42,
"input_tokens": 123456,
"output_tokens": 65432,
"total_ms": 345000
}
],
"tenant_id": "tn_xyz"
}
Platform-wide status overview: total agents, runs, success rate, average latency.
All agents status summary.
Detailed status for a single agent.
Agent health score.
Platform metrics snapshot for monitoring dashboards.
Unauthenticated health check endpoint.
Response (200):
{ "status": "ok", "version": "0.1.0" }
Root endpoint with service information.
Response (200):
{
"service": "AgentPaaS",
"version": "0.1.0",
"docs": "/docs",
"description": "Agent Platform as a Service -- Every agent is a Lambda term."
}
All errors follow a consistent structure:
{
"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) |
All responses include:
X-Content-Type-Options: nosniffX-Frame-Options: DENYX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-originX-Response-Time-Ms: <ms>X-Request-ID: <uuid> (for log correlation)Production-only:
Strict-Transport-Security: max-age=31536000; includeSubDomainsContent-Security-Policy: default-src 'self'Get async job status and result.
Response (200):
{
"job_id": "job_abc",
"status": "completed",
"result": "...",
"created_at": "..."
}
Status values: pending, running, completed, failed, cancelled.
Cancel a running or pending async job.
Response (200):
{ "message": "Job cancelled", "job_id": "job_abc" }