Skip to main content

Overview

The Playground API provides endpoints for managing chat sessions, sending messages, and retrieving observability data. All endpoints (except health) require JWT authentication.

Base URL

# Development
http://localhost:8002

# Test Infrastructure
http://localhost:9002

# Production
https://playground.yourdomain.com

Authentication

All endpoints except /api/playground/health require JWT authentication:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...

Health Endpoints

GET /api/playground/health

Health check endpoint (no authentication required). Response:
{
  "status": "healthy",
  "version": "1.0.0",
  "dependencies": {
    "redis": "healthy",
    "mcp_server": "healthy"
  }
}
Status Codes:
200
Success
Service is healthy
503
Service Unavailable
One or more dependencies are unhealthy
  {
    "status": "unhealthy",
    "dependencies": {
      "redis": "unhealthy",
      "mcp_server": "healthy"
    }
  }

Session Endpoints

POST /api/playground/sessions

Create a new chat session.
name
string
Display name for the session (optional)
metadata
object
Custom metadata to attach to the session (optional)
Request:
curl -X POST http://localhost:9002/api/playground/sessions \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Chat Session",
    "metadata": {
      "project": "demo"
    }
  }'
Response:
{
  "session_id": "sess_abc123def456",
  "name": "My Chat Session",
  "user_id": "alice",
  "created_at": "2025-12-06T10:00:00Z",
  "updated_at": "2025-12-06T10:00:00Z",
  "metadata": {
    "project": "demo"
  }
}
Status Codes:
201
Created
Session created successfully
401
Unauthorized
Invalid or missing authentication token

GET /api/playground/sessions

List all sessions for the authenticated user.
limit
integer
default:"20"
Maximum number of sessions to return
offset
integer
default:"0"
Number of sessions to skip for pagination
Request:
curl http://localhost:9002/api/playground/sessions?limit=10 \
  -H "Authorization: Bearer $TOKEN"
Response:
[
  {
    "session_id": "sess_abc123def456",
    "name": "My Chat Session",
    "user_id": "alice",
    "created_at": "2025-12-06T10:00:00Z",
    "updated_at": "2025-12-06T10:30:00Z",
    "message_count": 5
  },
  {
    "session_id": "sess_xyz789",
    "name": "Test Session",
    "user_id": "alice",
    "created_at": "2025-12-05T09:00:00Z",
    "updated_at": "2025-12-05T09:15:00Z",
    "message_count": 3
  }
]

GET /api/playground/sessions/

Get details for a specific session including message history. Path Parameters:
session_id
string
required
The session ID
Request:
curl http://localhost:9002/api/playground/sessions/sess_abc123def456 \
  -H "Authorization: Bearer $TOKEN"
Response:
{
  "session_id": "sess_abc123def456",
  "name": "My Chat Session",
  "user_id": "alice",
  "created_at": "2025-12-06T10:00:00Z",
  "updated_at": "2025-12-06T10:30:00Z",
  "messages": [
    {
      "id": "msg_001",
      "role": "user",
      "content": "Hello, what can you help me with?",
      "timestamp": "2025-12-06T10:00:05Z"
    },
    {
      "id": "msg_002",
      "role": "assistant",
      "content": "I can help you with a variety of tasks...",
      "timestamp": "2025-12-06T10:00:08Z",
      "tool_calls": []
    }
  ],
  "metadata": {
    "model": "gemini-2.5-flash",
    "total_tokens": 150
  }
}
Status Codes:
200
Success
Session retrieved successfully
404
Not Found
Session does not exist or user lacks access

DELETE /api/playground/sessions/

Delete a session and all its messages. Request:
curl -X DELETE http://localhost:9002/api/playground/sessions/sess_abc123def456 \
  -H "Authorization: Bearer $TOKEN"
Response:
{
  "message": "Session deleted successfully"
}
Status Codes:
204
No Content
Session deleted successfully
404
Not Found
Session does not exist

Chat Endpoints

POST /api/playground/chat

Send a message and receive a response.
session_id
string
required
The session ID to send the message to
message
string
required
The user’s message content
stream
boolean
default:"false"
Enable streaming response (SSE)
Request (Non-Streaming):
curl -X POST http://localhost:9002/api/playground/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "sess_abc123def456",
    "message": "What is 2 + 2?"
  }'
Response:
{
  "message_id": "msg_003",
  "role": "assistant",
  "content": "2 + 2 equals 4.",
  "timestamp": "2025-12-06T10:30:05Z",
  "tool_calls": [],
  "usage": {
    "prompt_tokens": 25,
    "completion_tokens": 10,
    "total_tokens": 35
  }
}
Request (Streaming):
curl -X POST http://localhost:9002/api/playground/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "session_id": "sess_abc123def456",
    "message": "Explain machine learning",
    "stream": true
  }'
Streaming Response (SSE):
event: token
data: {"content": "Machine"}

event: token
data: {"content": " learning"}

event: token
data: {"content": " is"}

event: tool_call
data: {"name": "search", "args": {"query": "machine learning definition"}}

event: tool_result
data: {"content": "ML is a subset of AI..."}

event: end
data: {"usage": {"total_tokens": 150}}
Status Codes:
200
Success
Message processed successfully
400
Bad Request
Invalid request body
404
Not Found
Session does not exist

Observability Endpoints

GET /api/playground/observability/traces

Get OpenTelemetry traces for a session.
session_id
string
required
Filter traces by session ID
limit
integer
default:"50"
Maximum number of traces to return
Request:
curl "http://localhost:9002/api/playground/observability/traces?session_id=sess_abc123" \
  -H "Authorization: Bearer $TOKEN"
Response:
[
  {
    "trace_id": "abc123def456789",
    "span_id": "span_001",
    "operation": "chat.process",
    "duration_ms": 1250,
    "status": "OK",
    "attributes": {
      "model": "gemini-2.5-flash",
      "tokens": 150
    },
    "timestamp": "2025-12-06T10:30:00Z"
  }
]

GET /api/playground/observability/logs

Get structured logs for a session.
session_id
string
required
Filter logs by session ID
level
string
default:"INFO"
Minimum log level (DEBUG, INFO, WARN, ERROR)
Request:
curl "http://localhost:9002/api/playground/observability/logs?session_id=sess_abc123&level=INFO" \
  -H "Authorization: Bearer $TOKEN"
Response:
[
  {
    "timestamp": "2025-12-06T10:30:00Z",
    "level": "INFO",
    "message": "Processing chat message",
    "attributes": {
      "session_id": "sess_abc123",
      "message_length": 25
    }
  }
]

GET /api/playground/observability/metrics

Get metrics for a session. Request:
curl "http://localhost:9002/api/playground/observability/metrics?session_id=sess_abc123" \
  -H "Authorization: Bearer $TOKEN"
Response:
{
  "session_id": "sess_abc123",
  "message_count": 10,
  "total_tokens": 1500,
  "average_latency_ms": 850,
  "error_count": 0,
  "tool_call_count": 3
}

WebSocket API

WS /ws/playground/

Real-time bidirectional chat using WebSocket. Connection:
const ws = new WebSocket('ws://localhost:9002/ws/playground/sess_abc123');

ws.onopen = () => {
  // Authenticate
  ws.send(JSON.stringify({
    type: 'auth',
    token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...'
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};
Message Types:
// Authentication
{ "type": "auth", "token": "eyJ..." }

// Send chat message
{ "type": "chat", "message": "Hello!" }

// Cancel current response
{ "type": "cancel" }

// Ping (keepalive)
{ "type": "ping" }
Example Session:
const ws = new WebSocket('ws://localhost:9002/ws/playground/sess_abc123');

ws.onopen = () => {
  // Step 1: Authenticate
  ws.send(JSON.stringify({ type: 'auth', token: TOKEN }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  switch (msg.type) {
    case 'auth_success':
      // Step 2: Send chat message
      ws.send(JSON.stringify({ type: 'chat', message: 'Hello!' }));
      break;

    case 'token':
      // Step 3: Handle streaming tokens
      process.stdout.write(msg.content);
      break;

    case 'tool_call':
      console.log(`\nTool: ${msg.name}(${JSON.stringify(msg.args)})`);
      break;

    case 'end':
      console.log(`\nTotal tokens: ${msg.usage.total_tokens}`);
      break;

    case 'error':
      console.error('Error:', msg.message);
      break;
  }
};

Error Responses

All endpoints may return the following errors:

401 Unauthorized

{
  "error": "unauthorized",
  "message": "Invalid or expired token",
  "code": "AUTH_INVALID_TOKEN"
}

403 Forbidden

{
  "error": "forbidden",
  "message": "Access denied to this resource",
  "code": "AUTH_ACCESS_DENIED"
}

404 Not Found

{
  "error": "not_found",
  "message": "Session not found",
  "code": "SESSION_NOT_FOUND"
}

429 Too Many Requests

{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Please try again later.",
  "retry_after": 60,
  "code": "RATE_LIMIT"
}

500 Internal Server Error

{
  "error": "internal_error",
  "message": "An unexpected error occurred",
  "trace_id": "abc123...",
  "code": "INTERNAL_ERROR"
}

SDK Examples

Python

import httpx

class PlaygroundClient:
    def __init__(self, base_url: str, token: str):
        self.client = httpx.AsyncClient(
            base_url=base_url,
            headers={"Authorization": f"Bearer {token}"}
        )

    async def create_session(self, name: str = None) -> dict:
        response = await self.client.post(
            "/api/playground/sessions",
            json={"name": name}
        )
        return response.json()

    async def chat(self, session_id: str, message: str) -> dict:
        response = await self.client.post(
            "/api/playground/chat",
            json={"session_id": session_id, "message": message}
        )
        return response.json()

    async def delete_session(self, session_id: str) -> None:
        await self.client.delete(f"/api/playground/sessions/{session_id}")

# Usage
client = PlaygroundClient("http://localhost:9002", token)
session = await client.create_session("My Session")
response = await client.chat(session["session_id"], "Hello!")
print(response["content"])

JavaScript/TypeScript

class PlaygroundClient {
  private baseUrl: string;
  private token: string;

  constructor(baseUrl: string, token: string) {
    this.baseUrl = baseUrl;
    this.token = token;
  }

  async createSession(name?: string): Promise<Session> {
    const response = await fetch(`${this.baseUrl}/api/playground/sessions`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ name })
    });
    return response.json();
  }

  async *streamChat(sessionId: string, message: string): AsyncGenerator<ChatEvent> {
    const response = await fetch(`${this.baseUrl}/api/playground/chat`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.token}`,
        'Content-Type': 'application/json',
        'Accept': 'text/event-stream'
      },
      body: JSON.stringify({ session_id: sessionId, message, stream: true })
    });

    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value);
      for (const line of chunk.split('\n')) {
        if (line.startsWith('data: ')) {
          yield JSON.parse(line.slice(6));
        }
      }
    }
  }
}

// Usage
const client = new PlaygroundClient('http://localhost:9002', token);
const session = await client.createSession('My Session');

for await (const event of client.streamChat(session.session_id, 'Hello!')) {
  if (event.type === 'token') {
    process.stdout.write(event.content);
  }
}


Full API access! Use these endpoints to build custom integrations with the Interactive Playground.