Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Evincere/klisk/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Klisk’s production server exposes a REST API for programmatic access to your agent:
  • POST /api/chat — Send messages, get responses
  • GET /api/info — Get agent metadata
  • GET /health — Health check endpoint
All endpoints support CORS and optional API key authentication.

Quick Example

curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Hello!",
    "stream": false
  }'
Response:
{
  "response": "Hi! How can I help you today?",
  "state": {},
  "done": true
}

Authentication

API Key Setup

Set an API key in your .env file:
.env
KLISK_API_KEY=sk-your-secret-key-here
You can set multiple keys separated by commas:
KLISK_API_KEY=sk-key-1,sk-key-2,sk-key-3

Supported Environment Variables

KLISK_API_KEY
string
Primary API key for all endpoints
KLISK_CHAT_KEY
string
Alternative key specifically for /api/chat and /ws/chat
KLISK_WIDGET_KEY
string
Alternative key for widget authentication
If any of these variables is set, authentication is required for all requests. The server accepts any of the configured keys.

Making Authenticated Requests

Include the API key in the Authorization header:
curl -X POST http://localhost:8080/api/chat \
  -H "Authorization: Bearer sk-your-secret-key-here" \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello!", "stream": false}'
Unauthorized Response:
{
  "error": "Invalid API key"
}
HTTP status: 401 Unauthorized

POST /api/chat

Send a message to your agent and receive a response.

Request Body

message
string
required
The user message to send to the agent
stream
boolean
default:true
Whether to stream the response (SSE) or return complete response
state
object
Conversation state from previous response (for multi-turn conversations)
agent_name
string
Specific agent to use (if multiple agents defined). Defaults to first agent.
attachments
array
Array of file attachments (images, PDFs). Each attachment should have:
  • mime_type (string): MIME type (e.g., image/jpeg, application/pdf)
  • data (string): Base64-encoded file data
  • name (string): Filename

Non-Streaming Response

Request:
{
  "message": "What is 2+2?",
  "stream": false
}
Response:
{
  "response": "2 + 2 equals 4.",
  "state": {
    "previous_response_id": "resp_abc123",
    "conversation_history": [...],
    "current_agent_name": "Assistant"
  },
  "done": true
}
response
string
The complete agent response text
state
object
Conversation state to pass in subsequent requests
done
boolean
Whether the response is complete (always true for non-streaming)

Streaming Response (SSE)

Request:
{
  "message": "Tell me a story",
  "stream": true
}
Response: Server-Sent Events (SSE) stream
data: {"type": "token", "data": "Once"}

data: {"type": "token", "data": " upon"}

data: {"type": "token", "data": " a"}

data: {"type": "token", "data": " time"}

data: {"type": "done", "data": "Once upon a time...", "response_id": "resp_xyz789"}

data: [DONE]

Event Types

token
object
Text token from the agent responseFields:
  • type: "token"
  • data: Text content (string)
thinking
object
Reasoning/thinking from reasoning models (o-series, gpt-5+)Fields:
  • type: "thinking"
  • data: Reasoning text (string)
tool_call
object
Tool call initiated by the agentFields:
  • type: "tool_call"
  • data:
    • tool (string): Tool name
    • arguments (string): JSON string of arguments
    • status (string): "running"
tool_result
object
Tool execution resultFields:
  • type: "tool_result"
  • data:
    • output (string): Tool output
done
object
Response completeFields:
  • type: "done"
  • data: Complete response text (string)
  • response_id: OpenAI response ID for conversation continuity (string, optional)
error
object
Error occurredFields:
  • type: "error"
  • data: Error message (string)

Multi-Turn Conversations

Pass the state from the previous response to maintain conversation context:
{
  "message": "What did I just ask?",
  "stream": false,
  "state": {
    "previous_response_id": "resp_abc123",
    "conversation_history": [...],
    "current_agent_name": "Assistant"
  }
}
Do not modify the state object. Pass it exactly as received from the previous response.

File Attachments

Send images or PDFs with your message:
{
  "message": "What's in this image?",
  "stream": false,
  "attachments": [
    {
      "mime_type": "image/jpeg",
      "data": "base64-encoded-image-data...",
      "name": "photo.jpg"
    }
  ]
}
Supported MIME types:
  • Images: image/jpeg, image/png, image/gif, image/webp
  • Documents: application/pdf
Size limit: 20MB per attachment

WebSocket Endpoint

For real-time bidirectional communication, use the WebSocket endpoint:
ws://localhost:8080/ws/chat

Authentication

Pass the API key as a query parameter:
ws://localhost:8080/ws/chat?key=sk-your-secret-key-here
Unauthorized Response:
{"type": "auth_error", "data": "Invalid API key"}
Connection closes with code 4001.

Sending Messages

Send JSON messages to the WebSocket:
{
  "message": "Hello!",
  "agent_name": "Assistant",
  "attachments": [...],
  "previous_response_id": "resp_abc123"
}

Receiving Events

Receive the same event types as the SSE stream:
{"type": "token", "data": "Hello"}
{"type": "token", "data": " there"}
{"type": "done", "data": "Hello there!", "response_id": "resp_xyz789"}

Clearing Conversation

Reset the conversation state:
{"type": "clear"}

Example: JavaScript Client

const ws = new WebSocket('ws://localhost:8080/ws/chat?key=sk-your-key');

ws.onopen = () => {
  ws.send(JSON.stringify({
    message: 'Hello, agent!'
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  
  if (data.type === 'token') {
    process.stdout.write(data.data);
  } else if (data.type === 'done') {
    console.log('\n\nComplete response:', data.data);
    console.log('Response ID:', data.response_id);
  } else if (data.type === 'error') {
    console.error('Error:', data.data);
  }
};

GET /api/info

Get metadata about the deployed agent. Request:
curl http://localhost:8080/api/info
Response:
{
  "name": "my-agent",
  "agent": "Assistant",
  "auth_required": true
}
name
string
Project name from klisk.config.yaml
agent
string
Default agent name (first agent if multiple defined)
auth_required
boolean
Whether API key authentication is enabled

GET /health

Health check endpoint for monitoring. Request:
curl http://localhost:8080/health
Response:
{
  "status": "ok"
}
HTTP status: 200 OK
The /health endpoint does not require authentication, even when KLISK_API_KEY is set.

Example Integrations

Python

Non-Streaming

import requests

url = "http://localhost:8080/api/chat"
headers = {
    "Authorization": "Bearer sk-your-secret-key",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, json={
    "message": "What is the capital of France?",
    "stream": False
})

data = response.json()
print(data["response"])

Streaming (SSE)

import requests
import json

url = "http://localhost:8080/api/chat"
headers = {
    "Authorization": "Bearer sk-your-secret-key",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, json={
    "message": "Tell me a story",
    "stream": True
}, stream=True)

for line in response.iter_lines():
    if line:
        line = line.decode('utf-8')
        if line.startswith('data: '):
            data_str = line[6:]  # Remove 'data: ' prefix
            if data_str == '[DONE]':
                break
            
            event = json.loads(data_str)
            if event['type'] == 'token':
                print(event['data'], end='', flush=True)
            elif event['type'] == 'done':
                print(f"\n\nComplete: {event['data']}")

JavaScript (Node.js)

Non-Streaming

const response = await fetch('http://localhost:8080/api/chat', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk-your-secret-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    message: 'What is 2+2?',
    stream: false
  })
});

const data = await response.json();
console.log(data.response);

Streaming (SSE)

const response = await fetch('http://localhost:8080/api/chat', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk-your-secret-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    message: 'Tell me a story',
    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);
  const lines = chunk.split('\n');
  
  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const dataStr = line.slice(6);
      if (dataStr === '[DONE]') break;
      
      const event = JSON.parse(dataStr);
      if (event.type === 'token') {
        process.stdout.write(event.data);
      } else if (event.type === 'done') {
        console.log('\n\nComplete:', event.data);
      }
    }
  }
}

cURL with Streaming

curl -X POST http://localhost:8080/api/chat \
  -H "Authorization: Bearer sk-your-secret-key" \
  -H "Content-Type: application/json" \
  -N \
  -d '{
    "message": "Count to 5",
    "stream": true
  }'
The -N flag disables buffering to see events in real-time.

Rate Limiting

Klisk does not implement built-in rate limiting. For production deployments, consider:
  • Cloud Run: Configure max instances to limit concurrency
  • API Gateway: Use Google Cloud API Gateway or similar
  • Nginx: Add rate limiting in reverse proxy

CORS

CORS is enabled for all origins by default:
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
This allows your API to be called from any web application.

Error Handling

HTTP Status Codes

  • 200 OK — Request successful
  • 401 Unauthorized — Invalid or missing API key
  • 500 Internal Server Error — Server error

Error Response Format

Non-streaming errors:
{
  "error": "Error message here"
}
Streaming errors:
data: {"type": "error", "data": "Error message here"}

Common Errors

No agents loaded:
{"type": "error", "data": "No agents loaded"}
Agent SDK object not available:
{"type": "error", "data": "Agent SDK object not available"}
Tool execution failed:
data: {"type": "error", "data": "Tool 'search' raised: ConnectionError"}

Next Steps

Production Server

Learn about klisk serve configuration

Deploy to Cloud Run

Deploy your API to production