{ "openapi": "3.0.0", "paths": { "/api/v1/agents": { "get": { "operationId": "AgentsAgentController_findAll", "parameters": [], "responses": { "200": { "description": "List of agents", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AgentResponse" } } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "List channels (agents) accessible by this API key", "tags": [ "Agents" ] }, "post": { "operationId": "AgentsAgentController_create", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateAgentDto" } } } }, "responses": { "201": { "description": "Agent created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Create a new channel (agent)", "tags": [ "Agents" ] } }, "/api/v1/agents/setWebhook": { "post": { "description": "Register a webhook URL that will receive events (message:created, review:responded) for the given channel. Replaces any previously configured webhook.", "operationId": "AgentsAgentController_setWebhook", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetWebhookDto" } } } }, "responses": { "200": { "description": "Webhook configured", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Set webhook URL for a channel", "tags": [ "Agents" ] } }, "/api/v1/agents/deleteWebhook": { "post": { "description": "Removes the currently configured webhook so no more events are delivered via HTTP callback.", "operationId": "AgentsAgentController_deleteWebhook", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteWebhookDto" } } } }, "responses": { "200": { "description": "Webhook removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Remove webhook URL from a channel", "tags": [ "Agents" ] } }, "/api/v1/status/ping": { "post": { "operationId": "AgentStatusController_ping", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PingStatusDto" } } } }, "responses": { "200": { "description": "Status updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Report agent status (heartbeat)", "tags": [ "Status" ] } }, "/api/v1/messages": { "post": { "operationId": "MessagesAgentController_create", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateMessageDto" } } } }, "responses": { "201": { "description": "Message created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageItemResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Send a message to a channel (channelId in body)", "tags": [ "Messages" ] }, "get": { "operationId": "MessagesAgentController_findAll", "parameters": [ { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } }, { "name": "limit", "required": false, "in": "query", "description": "Max results (default 50)", "schema": { "type": "string" } }, { "name": "cursor", "required": false, "in": "query", "description": "Cursor for pagination", "schema": { "type": "string" } }, { "name": "search", "required": false, "in": "query", "description": "Full-text search in message text", "schema": { "type": "string" } }, { "name": "has_attachments", "required": false, "in": "query", "description": "Filter messages with attachments (true/false)", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Paginated messages", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedMessagesResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "List messages for a channel (chat-as-storage)", "tags": [ "Messages" ] } }, "/api/v1/messages/iterations/{id}": { "get": { "operationId": "MessagesAgentController_getIterationChain", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } }, { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Iteration chain with all messages sorted by iteration" }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Message not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Get all messages in an iteration chain", "tags": [ "Messages" ] } }, "/api/v1/messages/{id}": { "get": { "operationId": "MessagesAgentController_findOne", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } }, { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Message details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageItemResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Message not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Get a single message + review status", "tags": [ "Messages" ] }, "delete": { "operationId": "MessagesAgentController_remove", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } }, { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Message deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeletedResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Message not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Delete (retract) a message", "tags": [ "Messages" ] } }, "/api/v1/messages/{id}/ack": { "post": { "operationId": "MessagesAgentController_acknowledge", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } }, { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Message acknowledged", "content": { "application/json": { "schema": { "type": "object", "properties": { "acknowledged": { "type": "boolean", "example": true } } } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Message not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Acknowledge receipt of a message", "tags": [ "Messages" ] } }, "/api/v1/reviews/pending": { "get": { "operationId": "ReviewsAgentController_getPending", "parameters": [ { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } } ], "responses": { "200": { "description": "List of messages with pending reviews", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/MessageItemResponse" } } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "List all pending reviews for a channel", "tags": [ "Reviews" ] } }, "/api/v1/reviews/{id}": { "get": { "operationId": "ReviewsAgentController_getReview", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } }, { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Message with review", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageItemResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Message or review not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Get a specific review by message ID", "tags": [ "Reviews" ] } }, "/api/v1/reviews/{id}/wait": { "get": { "operationId": "ReviewsAgentController_waitForResponse", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } }, { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } }, { "name": "timeout", "required": false, "in": "query", "description": "Timeout in ms (default 30000, max 30000)", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Review completed or timeout", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewWaitResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Message or review not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Long-poll for review response (max 30s)", "tags": [ "Reviews" ] } }, "/api/v1/files": { "get": { "operationId": "FilesAgentController_findAll", "parameters": [ { "name": "channel", "required": true, "in": "query", "description": "Channel (agent) ID", "schema": { "type": "string" } } ], "responses": { "200": { "description": "List of attachments", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AttachmentResponse" } } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your agent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "List all files in a channel", "tags": [ "Files" ] } }, "/api/v1/files/upload": { "post": { "operationId": "FilesAgentController_upload", "parameters": [], "responses": { "201": { "description": "Uploaded attachment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AttachmentResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Upload a file", "tags": [ "Files" ] } }, "/api/v1/files/store": { "post": { "operationId": "FilesAgentController_store", "parameters": [], "responses": { "201": { "description": "Stored attachment (orphan)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AttachmentResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Store a file without creating a message", "tags": [ "Files" ] } }, "/api/v1/files/store-text": { "post": { "operationId": "FilesAgentController_storeText", "parameters": [], "responses": { "201": { "description": "Stored text attachment (orphan)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AttachmentResponse" } } } }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Store text content as a file without creating a message", "tags": [ "Files" ] } }, "/api/v1/files/{id}/download": { "get": { "operationId": "FilesAgentController_download", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "File stream" }, "401": { "description": "Invalid API key", "content": { "application/octet-stream": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Not your file", "content": { "application/octet-stream": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Attachment not found", "content": { "application/octet-stream": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Download file directly by attachment ID", "tags": [ "Files" ] } }, "/api/v1/plugins": { "get": { "operationId": "PluginsAgentController_findAll", "parameters": [], "responses": { "200": { "description": "List of plugin manifests" }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "List installed plugins", "tags": [ "Plugins" ] } }, "/api/v1/plugins/{name}": { "get": { "operationId": "PluginsAgentController_findOne", "parameters": [ { "name": "name", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Plugin manifest" }, "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Plugin not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "api-key": [] } ], "summary": "Get plugin details", "tags": [ "Plugins" ] } } }, "info": { "title": "Placet API", "description": "Chat-based agent inbox for AI-human interaction", "version": "0.1.0", "contact": {} }, "tags": [], "servers": [ { "url": "http://localhost:3001", "description": "Local development" } ], "components": { "securitySchemes": { "bearer": { "scheme": "bearer", "bearerFormat": "JWT", "type": "http" }, "api-key": { "type": "apiKey", "in": "header", "name": "x-api-key", "description": "Placet API key (hp_...)" }, "cookie": { "type": "apiKey", "in": "cookie", "name": "access_token" } }, "schemas": { "ZodValidationError": { "type": "object", "properties": { "code": { "type": "string", "example": "invalid_type" }, "message": { "type": "string", "example": "Expected string, received number" }, "path": { "example": [ "email" ], "type": "array", "items": { "type": "string" } } }, "required": [ "code", "message", "path" ] }, "ErrorResponse": { "type": "object", "properties": { "statusCode": { "type": "number", "example": 400 }, "message": { "type": "string", "example": "Validation failed" }, "errors": { "description": "Zod validation errors (only on 400)", "type": "array", "items": { "$ref": "#/components/schemas/ZodValidationError" } } }, "required": [ "statusCode", "message" ] }, "DeletedResponse": { "type": "object", "properties": { "deleted": { "type": "boolean", "example": true } }, "required": [ "deleted" ] }, "AgentResponse": { "type": "object", "properties": { "id": { "type": "string", "example": "clxyz456" }, "name": { "type": "string", "example": "My Agent" }, "description": { "type": "string", "example": "A helpful assistant" }, "avatarUrl": { "type": "string", "example": "https://example.com/avatar.png" }, "webhookUrl": { "type": "string", "example": "https://example.com/webhook" }, "lastActiveAt": { "type": "string", "example": "2025-01-01T12:00:00.000Z" }, "createdAt": { "type": "string", "example": "2025-01-01T00:00:00.000Z" } }, "required": [ "id", "name", "createdAt" ] }, "CreateAgentDto": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "avatarUrl": { "type": "string", "format": "uri" }, "webhookUrl": { "type": "string", "format": "uri" } }, "required": [ "name" ] }, "SetWebhookDto": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" }, "channelId": { "type": "string", "minLength": 1 }, "headers": { "type": "object", "additionalProperties": { "type": "string" } }, "auth": { "$ref": "#/components/schemas/SetWebhookDtoAuth" } }, "required": [ "url", "channelId" ] }, "DeleteWebhookDto": { "type": "object", "properties": { "channelId": { "type": "string", "minLength": 1 } }, "required": [ "channelId" ] }, "PingStatusDto": { "type": "object", "properties": { "agentId": { "type": "string", "minLength": 1 }, "status": { "type": "string", "enum": [ "active", "busy", "error", "offline" ] }, "message": { "type": "string", "maxLength": 500 } }, "required": [ "agentId", "status" ] }, "AttachmentResponse": { "type": "object", "properties": { "id": { "type": "string", "example": "clxyz789" }, "messageId": { "type": "string", "example": "clxyz123" }, "pluginType": { "type": "string", "example": "file" }, "filename": { "type": "string", "example": "report.pdf" }, "mimeType": { "type": "string", "example": "application/pdf" }, "size": { "type": "number", "example": 1024 }, "storageKey": { "type": "string", "example": "uploads/clxyz123/report.pdf" }, "createdAt": { "type": "string", "example": "2025-01-01T00:00:00.000Z" } }, "required": [ "id", "messageId", "pluginType", "filename", "mimeType", "size", "storageKey", "createdAt" ] }, "MessageItemResponse": { "type": "object", "properties": { "id": { "type": "string", "example": "clxyz111" }, "channelId": { "type": "string", "example": "clxyz456" }, "senderType": { "type": "string", "example": "agent", "enum": [ "agent", "user" ] }, "senderId": { "type": "string", "example": "clxyz456" }, "text": { "type": "string", "example": "Hello from agent" }, "status": { "type": "string", "example": "info", "enum": [ "info", "success", "warning", "error" ] }, "review": { "type": "object", "example": { "type": "approval", "status": "pending" }, "description": "Review object (null if no review)" }, "metadata": { "type": "object", "example": { "source": "automation" }, "description": "Arbitrary metadata" }, "createdAt": { "type": "string", "example": "2025-01-01T00:00:00.000Z" }, "attachments": { "type": "array", "items": { "$ref": "#/components/schemas/AttachmentResponse" } } }, "required": [ "id", "channelId", "senderType", "senderId", "createdAt", "attachments" ] }, "PaginatedMessagesResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/MessageItemResponse" } }, "nextCursor": { "type": "object", "example": "clxyz999", "description": "Cursor for next page, null if no more", "nullable": true } }, "required": [ "data" ] }, "CreateMessageDto": { "type": "object", "properties": { "channelId": { "type": "string", "minLength": 1 }, "text": { "type": "string" }, "status": { "type": "string", "enum": [ "info", "success", "warning", "error" ] }, "review": { "$ref": "#/components/schemas/CreateMessageDtoReview" }, "metadata": { "type": "object", "additionalProperties": {} }, "webhookUrl": { "type": "string", "format": "uri" }, "attachmentIds": { "type": "array", "items": { "type": "string" } }, "textAttachments": { "type": "array", "items": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1 }, "filename": { "default": "content.md", "type": "string", "minLength": 1 }, "mimeType": { "default": "text/markdown", "type": "string" } }, "required": [ "content" ] } }, "iterationOf": { "type": "string" } }, "required": [ "channelId" ] }, "ReviewWaitResponse": { "type": "object", "properties": { "status": { "type": "string", "example": "completed", "enum": [ "completed", "timeout" ] }, "message": { "$ref": "#/components/schemas/MessageItemResponse" } }, "required": [ "status" ] }, "SetWebhookDtoAuth": { "type": "object", "properties": { "username": { "type": "string" }, "password": { "type": "string" } }, "required": [ "username", "password" ] }, "CreateMessageDtoReviewCallback": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" }, "method": { "type": "string" }, "headers": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "url" ] }, "CreateMessageDtoReview": { "type": "object", "properties": { "type": { "type": "string" }, "payload": { "type": "object", "additionalProperties": {} }, "callback": { "$ref": "#/components/schemas/CreateMessageDtoReviewCallback", "nullable": true }, "expiresAt": { "type": "string", "nullable": true }, "expiresInSeconds": { "type": "integer", "maximum": 9007199254740991, "minimum": 0, "exclusiveMinimum": true } }, "required": [ "type" ] } } } }