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)These paths describe the public REST API (worken-api-public). Internal Worken services call a separate internal API using Worken-Organization, Worken-Project, and Worken-User headers behind an internal ingress; those headers are reserved for Worken's own services and are not part of the public REST surface.
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 |
