Base URL
http://localhost:8080/api/v1
Endpoints Summary
Shannon provides 19 REST endpoints across 4 categories:
Task Operations (8 endpoints)
| Endpoint | Description |
|---|
POST /tasks | Submit a new task |
POST /tasks/stream | Submit task and receive stream URL |
GET /tasks | List tasks with filters (limit, offset, status, session_id) |
GET /tasks/{id} | Get task status and result |
GET /tasks/{id}/events | Get persistent event history |
GET /tasks/{id}/timeline | Get deterministic Temporal timeline |
POST /tasks/{id}/cancel | Cancel a queued or running task |
POST /approvals/decision | Submit a human approval decision |
Streaming (2 endpoints)
| Endpoint | Description |
|---|
GET /stream/sse?workflow_id={id} | Server-Sent Events streaming |
GET /stream/ws?workflow_id={id} | WebSocket streaming |
Session Management (6 endpoints)
| Endpoint | Description |
|---|
GET /sessions | List sessions with pagination |
GET /sessions/{sessionId} | Get session details |
GET /sessions/{sessionId}/history | Get session conversation history |
GET /sessions/{sessionId}/events | Get session events (grouped by turn) |
PATCH /sessions/{sessionId} | Update session title (UUID or external_id) |
DELETE /sessions/{sessionId} | Delete session (soft delete; 204 idempotent) |
Health & Observability (3 endpoints)
| Endpoint | Auth Required | Description |
|---|
GET /health | No | Health check probe |
GET /readiness | No | Readiness probe (checks orchestrator) |
GET /openapi.json | No | OpenAPI 3.0 specification |
Authentication
Development: Authentication is disabled by default (GATEWAY_SKIP_AUTH=1).Production: Set GATEWAY_SKIP_AUTH=0 and use API keys.
curl -H "X-API-Key: sk_test_123456" \
http://localhost:8080/api/v1/tasks
SSE Streaming Authentication
Browser EventSource cannot send custom headers. In production, proxy SSE via your backend and inject X-API-Key or Bearer headers. Do not pass API keys in URL query parameters.
const eventSource = new EventSource(
`/api/v1/stream/sse?workflow_id=${id}`
);
| Header | Required | Description |
|---|
X-API-Key | Yes* | API authentication key |
Content-Type | Yes (POST) | application/json |
Idempotency-Key | No | Prevents duplicate submissions (24h cache) |
traceparent | No | W3C trace context for distributed tracing |
*Not required if GATEWAY_SKIP_AUTH=1
| Header | Description |
|---|
X-Workflow-ID | Temporal workflow identifier for tracking |
X-Session-ID | Session identifier |
X-RateLimit-Limit | Requests allowed per minute |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when limit resets |
Rate Limiting
- Default: 60 requests/minute per API key
- Status:
429 Too Many Requests when exceeded
- Header:
Retry-After indicates seconds to wait
{
"error": "Rate limit exceeded",
"retry_after": 60
}
Idempotency
Prevent duplicate task submissions using Idempotency-Key header:
curl -X POST http://localhost:8080/api/v1/tasks \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{"query": "Analyze data"}'
Behavior:
- Same key within 24 hours returns cached response
- Request body is ignored for duplicate keys
- Uses Redis for distributed cache
Error Handling
HTTP Status Codes
| Code | Meaning | Common Causes |
|---|
200 | Success | Request completed |
201 | Created | Task submitted successfully |
400 | Bad Request | Invalid JSON, missing required fields |
401 | Unauthorized | Missing or invalid API key |
404 | Not Found | Task/session not found |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server error |
502 | Bad Gateway | Orchestrator unavailable |
503 | Service Unavailable | System overloaded |
{
"error": "Task not found"
}
CORS
CORS is enabled for development:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-API-Key, Idempotency-Key, traceparent
Production: Configure Access-Control-Allow-Origin to specific domains.
Timeouts
| Operation | Timeout |
|---|
| HTTP Read | 30 seconds |
| HTTP Write | 30 seconds |
| HTTP Idle | 60 seconds |
| Agent Execution | 10 minutes (configurable via AGENT_TIMEOUT_SECONDS) |
Best Practices
1. Always Use Idempotency Keys
import uuid
import requests
response = requests.post(
"http://localhost:8080/api/v1/tasks",
headers={
"X-API-Key": "sk_test_123456",
"Idempotency-Key": str(uuid.uuid4())
},
json={"query": "Analyze data"}
)
2. Implement Exponential Backoff
import time
def submit_with_retry(query, max_retries=3):
for attempt in range(max_retries):
response = requests.post(url, json={"query": query})
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
time.sleep(retry_after)
continue
return response
3. Stream Events for Long Tasks
import httpx
with httpx.stream(
"GET",
f"http://localhost:8080/api/v1/stream/sse?workflow_id={task_id}",
headers={"X-API-Key": "sk_test_123456"}
) as response:
for line in response.iter_lines():
if line.startswith("data:"):
event = json.loads(line[5:])
print(event["type"])
response = requests.post(
"http://localhost:8080/api/v1/tasks",
headers={"X-API-Key": "sk_test_123456"},
json={"query": "Analyze data"}
)
workflow_id = response.headers.get("X-Workflow-ID")
# Use workflow_id for streaming or Temporal UI
Quick Example
#!/bin/bash
API_KEY="sk_test_123456"
BASE="http://localhost:8080/api/v1"
# Submit task
RESPONSE=$(curl -s -X POST "$BASE/tasks" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "What is 2+2?"}')
TASK_ID=$(echo $RESPONSE | jq -r '.task_id')
echo "Task: $TASK_ID"
# Get status
curl -s "$BASE/tasks/$TASK_ID" -H "X-API-Key: $API_KEY" | jq
# Stream events
curl -N "$BASE/stream/sse?workflow_id=$TASK_ID" -H "X-API-Key: $API_KEY"
Next Steps