Skip to main content

Base URL

http://localhost:8080/api/v1

Endpoints Summary

Shannon provides 19 REST endpoints across 4 categories:

Task Operations (8 endpoints)

EndpointDescription
POST /tasksSubmit a new task
POST /tasks/streamSubmit task and receive stream URL
GET /tasksList tasks with filters (limit, offset, status, session_id)
GET /tasks/{id}Get task status and result
GET /tasks/{id}/eventsGet persistent event history
GET /tasks/{id}/timelineGet deterministic Temporal timeline
POST /tasks/{id}/cancelCancel a queued or running task
POST /approvals/decisionSubmit a human approval decision

Streaming (2 endpoints)

EndpointDescription
GET /stream/sse?workflow_id={id}Server-Sent Events streaming
GET /stream/ws?workflow_id={id}WebSocket streaming

Session Management (6 endpoints)

EndpointDescription
GET /sessionsList sessions with pagination
GET /sessions/{sessionId}Get session details
GET /sessions/{sessionId}/historyGet session conversation history
GET /sessions/{sessionId}/eventsGet 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)

EndpointAuth RequiredDescription
GET /healthNoHealth check probe
GET /readinessNoReadiness probe (checks orchestrator)
GET /openapi.jsonNoOpenAPI 3.0 specification

Authentication

Development: Authentication is disabled by default (GATEWAY_SKIP_AUTH=1).Production: Set GATEWAY_SKIP_AUTH=0 and use API keys.

API Key Header

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}`
);

Common Headers

Request Headers

HeaderRequiredDescription
X-API-KeyYes*API authentication key
Content-TypeYes (POST)application/json
Idempotency-KeyNoPrevents duplicate submissions (24h cache)
traceparentNoW3C trace context for distributed tracing
*Not required if GATEWAY_SKIP_AUTH=1

Response Headers

HeaderDescription
X-Workflow-IDTemporal workflow identifier for tracking
X-Session-IDSession identifier
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix 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

CodeMeaningCommon Causes
200SuccessRequest completed
201CreatedTask submitted successfully
400Bad RequestInvalid JSON, missing required fields
401UnauthorizedMissing or invalid API key
404Not FoundTask/session not found
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer error
502Bad GatewayOrchestrator unavailable
503Service UnavailableSystem overloaded

Error Response Format

{
  "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

OperationTimeout
HTTP Read30 seconds
HTTP Write30 seconds
HTTP Idle60 seconds
Agent Execution10 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"])

4. Extract Workflow ID from Response

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