API Reference
All endpoints are relative to https://api.worken.ru. Every request must include:
Authorization: Bearer sk-your-api-key
Content-Type: application/json (for POST / PATCH)Bots
Bots (also called virts) are AI agents that handle conversations.
Types
type BotStatus = 'active' | 'disabled' | 'error'
type Bot = {
id: string
name: string
description: string | null
status: BotStatus
project_id: string
created_at: string
updated_at: string
}
type BotSettings = {
ai: {
instruction: string
model: {
id: string // e.g. "openai/gpt-4o-mini"
temperature: number // 0.0–2.0
max_tokens: number
top_p: number
frequency_penalty: number
presence_penalty: number
}
memory: {
lastMessages: number
semanticRecall: boolean
workingMemory: { enabled: boolean }
generateTitle: boolean
}
formatting: {
removeEmojis: boolean
removeMarkdown: boolean
}
tools: Record<string, 'user_approve' | 'operator_approve' | 'auto'>
}
}List bots
GET /botsReturns all bots in the current project.
Response 200
type ListBotsResponse = Bot[]Create a bot
POST /botsBody
type CreateBotBody = {
name: string
}Response 200
type CreateBotResponse = BotExample
curl https://api.worken.ru/bots \
-X POST \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"name": "Sales Bot"}'Get a bot
GET /bots/:bot_idResponse 200 — Bot
Update a bot
POST /bots/:bot_idBody
type UpdateBotBody = {
name?: string
description?: string
}Response 200 — Bot
Update bot status
POST /bots/:bot_id/statusBody
type SetBotStatusBody = {
status: BotStatus
}Get bot settings
GET /bots/:bot_id/settingsResponse 200 — BotSettings
Update bot settings
POST /bots/:bot_id/settingsPartial updates are supported — only the provided fields are changed.
Body — partial BotSettings
Example — update model and instruction
curl https://api.worken.ru/bots/${BOT_ID}/settings \
-X POST \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"ai": {
"instruction": "You are a sales assistant. Focus on product benefits.",
"model": { "id": "openai/gpt-4o", "temperature": 0.7 }
}
}'Clone a bot
POST /bots/:bot_id/cloneCreates a new bot with identical settings. Useful for A/B testing configurations.
Response 200 — Bot
Delete a bot
POST /bots/:bot_id/deleteResponse 200
Chats
A chat is a channel through which users reach a bot — a Telegram group, a website widget, a WhatsApp inbox, etc.
Types
type ChatStatus = 'active' | 'disabled' | 'error'
type Chat = {
id: string
name: string
bot_id: string
integration_id: string | null
status: ChatStatus
project_id: string
created_at: string
updated_at: string
events_24h: number // message events in last 24 hours
}List chats
GET /chatsResponse 200
type ListChatsResponse = Chat[]Get a chat
GET /chats/:chat_idResponse 200 — Chat
List threads in a chat
GET /chats/:chat_id/threadsResponse 200
type Thread = {
id: string
chat_id: string
bot_id: string
mode: 'auto' | 'manual' | 'operator' | 'blocked'
title: string | null
last_message_at: string | null
pending_count: number
created_at: string
}
type ListThreadsResponse = Thread[]Stream a response (SSE)
Send a new user message and receive the AI response as a Server-Sent Events stream.
POST /chats/:chat_id/threads/:thread_id/streamBody
type StreamBody = {
messages: Array<{
role: 'user'
content: string
}>
scheduledAt?: string // ISO 8601 — defer the response
}Response — text/event-stream (Vercel AI SDK data stream v2)
// Events emitted during streaming
type StreamEvent =
| { type: 'text-delta'; textDelta: string }
| { type: 'tool-call'; toolName: string; args: unknown }
| { type: 'tool-result'; toolName: string; result: unknown }
| { type: 'finish'; finishReason: 'stop' | 'tool-calls' | 'length' }Example — using the SDK
const stream = await worken.chats.threads.stream(chatId, threadId, {
messages: [{ role: 'user', content: 'What is your return policy?' }],
})
for await (const chunk of stream) {
process.stdout.write(chunk.textDelta ?? '')
}Get thread messages
GET /chats/:chat_id/threads/:thread_id/messagesReturns the full message history from the agent's memory.
Response 200
type Message = {
id: string
role: 'user' | 'assistant' | 'tool'
content: string
created_at: string
}
type GetMessagesResponse = Message[]Delete a thread
POST /chats/:chat_id/threads/:thread_id/deleteRemoves the thread and its messages from memory.
Set thread mode
POST /chats/:chat_id/threads/:thread_id/modeBody
type SetThreadModeBody = {
mode: 'auto' | 'manual' | 'operator' | 'blocked'
}| Mode | Behaviour |
|---|---|
auto | AI handles all replies |
manual | Operator sends replies, AI is paused |
operator | Operator is composing; AI is paused |
blocked | No replies sent |
Threads
The /threads endpoint gives a project-wide view across all chats.
List threads
GET /threadsQuery parameters
| Parameter | Type | Description |
|---|---|---|
chat_id | string | Filter by chat |
bot_id | string | Filter by bot |
search | string | Full-text search in messages |
limit | number | Max results (default 20) |
offset | number | Pagination offset |
cursor | string | Cursor for real-time pagination |
Response 200
type ListThreadsResponse = {
data: Thread[]
next_cursor: string | null
}Get a thread
GET /threads/:thread_idResponse 200
type ThreadDetail = Thread & {
person: {
id: string
name: string | null
avatar_url: string | null
external_id: string | null
} | null
stats: {
messages_total: number
user_messages: number
bot_messages: number
}
}Send an operator message
POST /threads/:thread_id/sendSend a message as a human operator. The thread must be in manual mode.
Body
type SendMessageBody = {
text: string
scheduledAt?: string // defer delivery — ISO 8601
}Get working memory
GET /threads/:thread_id/memoryReturns the agent's current working memory for this thread — extracted facts the model retains across turns.
Response 200
type WorkingMemoryResponse = {
content: string | null // Markdown-formatted memory block
}Real-time events (SSE)
Subscribe to live updates for all threads in the project:
GET /threads/eventsOr for a single thread:
GET /threads/events/:thread_idEvent format
type ThreadEvent = {
thread_id: string
type: 'pending_count' | 'mode_changed' | 'message_created'
pending_count?: number
mode?: string
}Example
const eventSource = new EventSource(
'https://api.worken.ru/threads/events',
{ headers: { Authorization: `Bearer ${apiKey}` } }
)
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data) as ThreadEvent
console.log(`Thread ${data.thread_id} has ${data.pending_count} pending messages`)
}Integrations
Integrations connect your bots to external platforms.
Types
type IntegrationVendor =
| 'telegram' | 'whatsapp' | 'vk' | 'ok' | 'max'
| 'github' | 'google' | 'yandex'
| 'amocrm' | 'bitrix' | 'avito'
| 'sber' | 'worken'
type IntegrationStatus = 'active' | 'disabled' | 'error'
type Integration = {
id: string
name: string
vendor: IntegrationVendor
status: IntegrationStatus
project_id: string
created_at: string
updated_at: string
}List integrations
GET /integrationsResponse 200 — Integration[]
Create an integration
POST /integrationsBody
type CreateIntegrationBody = {
name: string
vendor: IntegrationVendor
auth_data: Record<string, unknown> // vendor-specific credentials
}Examples by vendor
// Telegram — bot token
{ vendor: 'telegram', auth_data: { token: '7123456789:AAH...' } }
// amoCRM — OAuth (after getting tokens via /integrations/:id/oauth/start)
{ vendor: 'amocrm', auth_data: { subdomain: 'mycompany' } }
// VK Communities — group access token
{ vendor: 'vk', auth_data: { access_token: 'vk1.a...' } }Get an integration
GET /integrations/:idResponse 200 — Integration
Update an integration
POST /integrations/:idBody
type UpdateIntegrationBody = {
name?: string
status?: IntegrationStatus
auth_data?: Record<string, unknown>
settings?: Record<string, unknown>
}Delete an integration
DELETE /integrations/:idGet integration profile
GET /integrations/:id/profileVerifies that the stored credentials are valid and returns the authenticated identity (e.g. bot username for Telegram, account email for Google).
Response 200
type IntegrationProfile = {
id: string
name: string
username?: string
avatar_url?: string
}OAuth flow
Start OAuth for integrations that use it (amoCRM, Bitrix24, Google, etc.):
POST /integrations/:id/oauth/startResponse 200
type OAuthStartResponse = {
url: string // redirect the user here
}After the user authorises, the platform redirects back and credentials are saved automatically.
Manage integration chats
// List chats for this integration
GET /integrations/:id/chats
// Create a new chat
POST /integrations/:id/chats
// body: { bot_id: string, name: string, settings?: object }
// Update a chat
POST /integrations/:id/chats/:chat_id
// Activate / deactivate
POST /integrations/:id/chats/:chat_id/status
// body: { status: 'active' | 'disabled' }
// Delete
DELETE /integrations/:id/chats/:chat_idBilling
Types
type BillingAccount = {
tariff: string
credits: number // main balance in credits
bonus: number // promotional credits
subscription_until: string | null // ISO 8601
}
type Transaction = {
id: string
type: 'charge' | 'topup' | 'bonus' | 'refund'
amount: number
description: string
created_at: string
}
type Invoice = {
id: string
status: 'pending' | 'paid' | 'cancelled'
amount: number
payment_url: string | null
created_at: string
}Get billing account
GET /billing/accountResponse 200 — BillingAccount
Get balance
GET /billing/balanceReturns current credit and bonus balances:
type BalanceResponse = {
credits: number
bonus: number
}List transactions
GET /billing/transactionsQuery parameters — limit (default 20), offset
Response 200
type ListTransactionsResponse = {
data: Transaction[]
total: number
}List invoices
GET /billing/invoicesResponse 200 — Invoice[]
Create an invoice (top up balance)
POST /billing/invoicesBody
type CreateInvoiceBody = {
offer_id: string
credits?: number // custom top-up amount
}Response 200
type CreateInvoiceResponse = {
invoice: Invoice
payment_url: string
}List billing offers
GET /billing/offersReturns available subscription plans and one-time top-up offers:
type BillingOffer = {
id: string
name: string
price: number
credits: number
description: string
}
type ListOffersResponse = BillingOffer[]Projects & API Keys
List projects
GET /projectsResponse 200
type Project = {
id: string
name: string
organization_id: string
avatar_url: string | null
created_at: string
}
type ListProjectsResponse = Project[]Create a project
POST /projectsBody
type CreateProjectBody = {
name: string
organization_id: string
}Create an API key
POST /projects/:id/api-keysBody
type CreateApiKeyBody = {
name: string
}Response 200
type CreateApiKeyResponse = {
id: string
name: string
key: string // shown only once — store it securely
created_at: string
}List API keys
GET /projects/:id/api-keysReturns key metadata — the secret value is never returned after creation.
Response 200
type ApiKey = {
id: string
name: string
last_used_at: string | null
created_at: string
}
type ListApiKeysResponse = ApiKey[]Delete an API key
DELETE /projects/:id/api-keys/:key_idVector Stores (Knowledge Bases)
Worken provides an OpenAI-compatible Vector Store API for grounding agents in documents.
Types
type VectorStore = {
id: string
name: string
file_count: number
status: 'ready' | 'indexing' | 'error'
created_at: string
}
type VectorStoreFile = {
id: string
filename: string
status: 'processed' | 'pending' | 'error'
created_at: string
}Endpoints
POST /vector_stores // create
GET /vector_stores // list
GET /vector_stores/:id // get
POST /vector_stores/:id // update
DELETE /vector_stores/:id // delete
POST /vector_stores/:id/files // add file
GET /vector_stores/:id/files // list files
GET /vector_stores/:id/files/:file_id // get file
DELETE /vector_stores/:id/files/:file_id // remove fileWebhook Endpoints
Register HTTP endpoints to receive real-time events from Worken.
Types
type WebhookEndpoint = {
id: string
url: string
status: 'active' | 'disabled'
created_at: string
}
type WebhookEvent = {
id: string
type: string // e.g. "thread.message.created"
created_at: string
data: Record<string, unknown>
}Endpoints
GET /webhook-endpoints // list
POST /webhook-endpoints // create { url, secret }
PUT /webhook-endpoints/:id // update { status?, secret? }
DELETE /webhook-endpoints/:id // deleteEvent types
| Event | Description |
|---|---|
thread.created | A new conversation started |
thread.message.created | New message in a thread |
thread.mode.changed | Thread switched to manual / auto |
integration.auth_lost | Integration credentials expired |
billing.balance.low | Credits balance below threshold |
Signature verification
Worken signs each webhook request with an HMAC-SHA256 signature using your secret:
import { createHmac } from 'node:crypto'
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const expected = createHmac('sha256', secret).update(body).digest('hex')
return expected === signature
}
// In your handler:
app.post('/webhook', (req, res) => {
const sig = req.headers['x-worken-signature'] as string
if (!verifyWebhook(req.rawBody, sig, process.env.WORKEN_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
// process event...
})Error codes
| HTTP status | Error | Description |
|---|---|---|
400 | Bad Request | Missing or invalid request body |
401 | Unauthorized | API key is missing or invalid |
403 | Forbidden | Key does not have access to this resource |
404 | Not Found | Resource does not exist |
409 | Conflict | Resource already exists (e.g. duplicate chat) |
422 | Unprocessable Entity | Validation failed — see message for details |
429 | Too Many Requests | Rate limit exceeded — see Retry-After header |
500 | Internal Server Error | Server error — contact support |
