Version: 1.0.0
This API facilitates the management of agents, chats, messages, workflows, CMS content, files, API keys, and webhooks within the Brightsy AI ecosystem, providing endpoints for creating, retrieving, updating, and deleting resources.
Base URL
https://brightsy.ai/api/v1beta
Authentication
The API uses bearer token authentication to secure its endpoints.
Type: HTTP Bearer Authentication
Format: Include your API key in the Authorization header
Authorization: Bearer YOUR_API_KEY
Managing API Keys
API keys can be created and managed in the Automations section:
- Navigate to Automations → API Keys
- Click Create API Key
- Configure permissions (agents, scenarios, CMS access)
- Copy the generated key (shown only once)
Timeouts
All API endpoints have a required timeout of 800 seconds. Clients should be configured to wait at least 300 seconds for a response before timing out the request. This is especially important for endpoints that perform complex processing or generate completions.
BrightsyClient SDK
The BrightsyClient provides a convenient JavaScript/TypeScript SDK for interacting with the Brightsy API. It handles authentication, request formatting, and provides type-safe methods for all API operations.
Installation
npm install @brightsy/client
Initialization
The SDK supports multiple authentication methods:
API Key Authentication (Default)
import { BrightsyClient } from '@brightsy/client';
const client = new BrightsyClient({
account_id: 'your-account-id',
api_key: 'your-api-key'
});
OAuth 2.1 Authentication (User-Authorized)
import { BrightsyClient, OAuthClient } from '@brightsy/client';
// For external agents or applications requiring user authorization
const client = new BrightsyClient({
authMode: 'oauth',
oauthAccessToken: 'user-access-token',
oauthRefreshToken: 'user-refresh-token',
oauthClientId: 'your-oauth-client-id',
oauthClientSecret: 'your-oauth-client-secret', // Optional, for confidential clients
oauthTokenExpiry: Date.now() + 3600 * 1000, // Optional, for automatic refresh
// Optional: Get notified when tokens are refreshed
onTokenRefresh: (accessToken, refreshToken) => {
console.log('Token refreshed automatically');
// Save new tokens to storage
saveTokens({ accessToken, refreshToken });
}
});
OAuth Features:
- ✅ Automatic token refresh before expiry (no interruption)
- ✅ PKCE support (S256) for security
- ✅ Dynamic client registration
- ✅ Token revocation on logout
- ✅ Works in browser and Node.js
Complete OAuth Flow Example:
import { OAuthClient } from '@brightsy/client';
// 1. Register OAuth client (one-time)
const oauthClient = new OAuthClient({
clientId: '', // Will be provided after registration
redirectUri: 'http://localhost:3000/callback'
});
const credentials = await oauthClient.register({
client_name: 'My Application',
redirect_uris: ['http://localhost:3000/callback'],
scopes: ['brightsy:api']
});
// 2. Start authorization flow
const { url, state, codeVerifier } = await oauthClient.buildAuthorizationUrl();
// Store state and codeVerifier, redirect user to url
// 3. Handle callback and exchange code for tokens
const tokens = await oauthClient.exchangeCode(authCode, codeVerifier);
// 4. Initialize client with tokens (auto-refresh enabled)
const client = new BrightsyClient({
authMode: 'oauth',
oauthAccessToken: tokens.access_token,
oauthRefreshToken: tokens.refresh_token,
oauthClientId: credentials.client_id,
oauthClientSecret: credentials.client_secret
});
// Use the client normally - tokens refresh automatically!
const agents = await client.agents.list();
For detailed OAuth documentation, see the OAuth Authentication Guide.
Cookie Authentication (Browser Sessions)
const client = new BrightsyClient({
authMode: 'cookie',
endpoint: 'https://your-instance.brightsy.ai'
});
External Auth Providers (Clerk, Auth0, etc.)
const client = new BrightsyClient({
authMode: 'external_auth',
externalAuthToken: 'clerk-or-auth0-token',
external_account_id: 'external-account-id'
});
Stream Processing
The SDK provides streaming utilities for processing streaming responses:
import { processStream, formatMessages, generateUUID } from '@brightsy/client';
import type { ChatMessage } from '@brightsy/client';
// Create a streaming request
const stream = await client.chat.completions('agent-id').create({
messages: [
{
role: 'user',
content: [{ text: 'Hello' }]
}
],
stream: true
});
// Keep track of prior messages (messages that existed before streaming started)
const priorMessages = [...existingMessages]; // Your existing message history
// Process stream - accumulates NEW messages from the stream
await processStream(stream, {
onMessagesUpdate: (streamedMessages: ChatMessage[]) => {
// Called whenever new content arrives during streaming
// streamedMessages contains only NEW messages from this stream (in Brightsy format)
// Combine with priorMessages for complete message history
const allMessages = [...priorMessages, ...streamedMessages];
// Convert to Vercel format with parts for rendering
const formattedMessages = formatMessages(allMessages);
// Update UI state
setMessages(formattedMessages);
},
onComplete: (streamedMessages: ChatMessage[]) => {
// Called when stream completes
// streamedMessages contains all NEW messages from this stream
const allMessages = [...priorMessages, ...streamedMessages];
const formattedMessages = formatMessages(allMessages);
setMessages(formattedMessages);
setStreaming(false);
},
onError: (error: Error) => {
// Called if an error occurs during streaming
console.error('Stream error:', error);
setStreaming(false);
}
});
Key Functions:
processStream(stream, callbacks)- Processes streaming responses and calls handlers with NEW messages from the stream in Brightsy formatformatMessages(messages)- Converts Brightsy format messages to Vercel AI SDK format withpartsfor renderinggenerateUUID()- Generates PostgreSQL-compliant UUIDs for message IDs
Important: processStream doesn't return messages - it calls your handlers (onMessagesUpdate, onComplete) with the NEW messages from the stream. Always combine with your prior message history ([...priorMessages, ...streamedMessages]) in the handlers before formatting for display.
Using formatMessages to Render Messages
The formatMessages function converts Brightsy format messages (with content arrays) to Vercel format messages (with parts arrays) for rendering:
import { formatMessages } from '@brightsy/client';
// Brightsy format messages (from API or processStream)
const brightsyMessages = [
{
id: 'msg-1',
role: 'user',
content: [{ text: 'Hello!' }],
createdAt: new Date().toISOString()
},
{
id: 'msg-2',
role: 'assistant',
content: [{ text: 'Hi! How can I help you?' }],
tool_calls: [
{
id: 'call-1',
type: 'function',
function: {
name: 'search',
arguments: '{"query":"example"}'
}
}
],
createdAt: new Date().toISOString()
},
{
id: 'msg-3',
role: 'tool',
tool_call_id: 'call-1',
name: 'search',
content: '{"results":["result1","result2"]}',
createdAt: new Date().toISOString()
}
];
// Convert to Vercel format with parts
const formattedMessages = formatMessages(brightsyMessages);
// Render the formatted messages
formattedMessages.forEach(message => {
console.log(`[${message.role}]:`, message.id);
message.parts.forEach(part => {
if (part.type === 'text') {
console.log(' Text:', part.text);
} else if (part.type === 'tool-invocation') {
console.log(' Tool:', part.toolInvocation.toolName);
console.log(' Args:', part.toolInvocation.args);
if (part.toolInvocation.result) {
console.log(' Result:', part.toolInvocation.result);
}
} else if (part.type === 'reasoning') {
console.log(' Reasoning:', part.reasoning);
} else if (part.type === 'source') {
console.log(' Source:', part.source.url, part.source.title);
} else if (part.type === 'image_url') {
console.log(' Image:', part.image_url.url);
} else if (part.type === 'file') {
console.log(' File:', part.file);
}
});
});
Output:
[user]: msg-1
Text: Hello!
[assistant]: msg-2
Text: Hi! How can I help you?
Tool: search
Args: { query: "example" }
Result: { results: ["result1", "result2"] }
Key Points:
formatMessagesmerges consecutive messages of the same role and tool/assistant messages- Tool calls and their results are combined into single
tool-invocationparts withstate: 'result' - The function handles text, tool invocations, reasoning, sources, images, and file attachments
- Usage information is accumulated when messages are merged
API Structure
The BrightsyClient uses a consistent property-based API pattern for all resource access:
CMS APIs (properties):
client.cma- Content Management APIclient.cda- Content Delivery APIclient.cpa- Content Preview API
Collection APIs (properties):
client.agents- Agent managementclient.scenarios- Scenario managementclient.schedules- Schedule managementclient.webhooks- Webhook managementclient.apps- App managementclient.files- File managementclient.images- Image operationsclient.mcpServers- MCP server managementclient.apikeys- API key managementclient.pageTypes- Page type managementclient.libs- Component library managementclient.sites- Site management
Agent APIs (methods, require IDs):
client.agent(agentId)- Access a specific agent.a2a- A2A Protocol operations (agent-to-agent communication).getCard()- Get agent's A2A card.tasks- Task management (create, get, stream, append, cancel).connections- External agent connections (create, list, delete)
client.scenario(scenarioId)- Access a specific scenario
Chat Completions (Vercel AI SDK-compliant):
client.chat.completions(agentId)- Stateless completions (provide full message history)client.chat.completions(agentId).chat(chatId)- Stateful workspace chat (add messages to existing chat, server maintains history).create({ message })- Add a message and get response.getMessages()- Get all messages from the chat.deleteMessage(messageId)- Delete a message from the chat
Stream Processing Utilities:
processStream(stream, callbacks)- Process streaming responses and accumulate messages in Brightsy formatformatMessages(messages)- Convert Brightsy format messages to Vercel AI SDK format with partsgenerateUUID()- Generate PostgreSQL-compliant UUIDs
OAuth Utilities (when using authMode: 'oauth'):
OAuthClient- Full OAuth 2.1 client with PKCE support.register(config)- Register new OAuth client.buildAuthorizationUrl()- Generate authorization URL.exchangeCode(code, verifier)- Exchange auth code for tokens.refreshToken(refreshToken)- Refresh access token.revokeToken(token)- Revoke token.getServerMetadata()- Get OAuth server metadata
TokenManager- Automatic token refresh managementclient.getOAuthClient()- Get OAuth client instanceclient.getOAuthToken()- Get current access token (refreshes if needed)client.isOAuthTokenExpired()- Check if token is expiredclient.refreshOAuthToken()- Manually refresh tokenclient.revokeOAuthTokens()- Revoke all tokens (logout)
Usage Examples
Chat Completions
// Stateless chat completion
// Note: Agents have their system prompt saved in their definition.
// You can optionally include system messages here to add context-specific instructions.
const response = await client.chat.completions('agent-id').create({
messages: [
{
role: 'system',
content: [
{ text: 'Additional context: The user is on the pricing page.' }
]
},
{
role: 'user',
content: [
{ text: 'Hello, how can you help me?' }
]
}
],
stream: false,
tools: [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get the current weather',
parameters: {
type: 'object',
properties: {
location: { type: 'string' }
}
}
}
}
],
max_tokens: 16000
});
// Response is in Brightsy format - convert to parts for rendering
const formattedMessages = formatMessages([response.choices[0].message]);
formattedMessages.forEach(message => {
message.parts.forEach(part => {
if (part.type === 'text') {
console.log('Text:', part.text);
} else if (part.type === 'tool-invocation') {
console.log('Tool:', part.toolInvocation.toolName);
console.log('Args:', part.toolInvocation.args);
console.log('Result:', part.toolInvocation.result);
} else if (part.type === 'reasoning') {
console.log('Reasoning:', part.reasoning);
}
});
});
// Streaming chat completions
const stream = await client.chat.completions('agent-id').create({
messages: [
{
role: 'user',
content: [{ text: 'Tell me a story' }]
}
],
stream: true
});
// Process stream using processStream utility
import { processStream, formatMessages } from '@brightsy/client';
import type { ChatMessage } from '@brightsy/client';
// Keep track of prior messages (messages that existed before streaming started)
const priorMessages = [...existingMessages]; // Your existing message history
// Process the stream - handlers are called as messages arrive
await processStream(stream, {
onMessagesUpdate: (streamedMessages: ChatMessage[]) => {
// Called whenever new content arrives during streaming
// streamedMessages contains only the NEW messages from this stream
// Combine with priorMessages for complete history
const allMessages = [...priorMessages, ...streamedMessages];
// Convert to parts format for rendering
const formattedMessages = formatMessages(allMessages);
// Update UI with formattedMessages
setMessages(formattedMessages); // Update your UI state
},
onComplete: (streamedMessages: ChatMessage[]) => {
// Called when stream completes
// streamedMessages contains all NEW messages from this stream
const allMessages = [...priorMessages, ...streamedMessages];
const formattedMessages = formatMessages(allMessages);
// Final UI update
setMessages(formattedMessages);
setStreaming(false);
console.log('Stream complete, total new messages:', streamedMessages.length);
},
onError: (error: Error) => {
// Called if an error occurs during streaming
console.error('Stream error:', error);
setStreaming(false);
}
});
// Stateful workspace chat - adds messages to existing chat
// The workspace maintains the message history on the server
const chatResponse = await client.chat.completions('agent-id').chat('chat-id').create({
message: {
role: 'user',
content: [{ text: 'Continue our conversation' }]
},
stream: false
});
// Get all messages from a workspace chat
const messages = await client.chat.completions('agent-id').chat('chat-id').getMessages();
console.log('Chat messages:', messages);
// Delete a message from workspace chat
await client.chat.completions('agent-id').chat('chat-id').deleteMessage('message-id');
Message Formats:
- Brightsy Format: Used internally and for API requests. Messages have
role,content(array),tool_calls,tool_call_id, etc. - Vercel Format: Used for rendering. Messages have
role,parts(array of MessagePart objects). Convert usingformatMessages().
Example Message Structure:
// Brightsy format (stored in state, sent to API)
const brightsyMessage = {
id: 'msg-123',
role: 'user',
content: [{ text: 'Hello' }],
createdAt: new Date().toISOString()
};
// Vercel format (for rendering)
const vercelMessage = formatMessages([brightsyMessage])[0];
// Result: { id: 'msg-123', role: 'user', parts: [{ type: 'text', text: 'Hello' }], ... }
Agents
// List all agents
const agents = await client.agents.list();
// Get a specific agent
const agent = await client.agents.get('agent-id');
A2A Protocol (Agent-to-Agent Communication)
The A2A protocol enables agents to communicate with other agents, both internal and external:
// Get agent's A2A card (capabilities)
const card = await client.agent(agentId).a2a.getCard();
// Create a new task
const task = await client.agent(agentId).a2a.tasks.create({
role: 'user',
content: [{ type: 'text', text: 'Hello!' }]
});
// Stream task updates in real-time (SSE)
await client.agent(agentId).a2a.tasks.stream(task.id, (update) => {
console.log('Status:', update.task_status);
console.log('Messages:', update.messages);
});
// Continue conversation (multi-turn)
await client.agent(agentId).a2a.tasks.append(task.id, {
role: 'user',
content: [{ type: 'text', text: 'Follow-up question' }]
});
// Connect to external A2A agent
await client.agent(agentId).a2a.connections.create({
endpoint: 'https://external-agent.com/a2a',
auth_config: { type: 'bearer', token: 'xyz' }
});
// List external connections
const connections = await client.agent(agentId).a2a.connections.list();
Note: For complete A2A documentation including multi-agent workflows, authentication, and best practices, see the A2A Protocol Guide.
CMS (Content Management API)
The CMS API provides three endpoints:
- CDA (Content Delivery API): Returns published records (read-only)
- CMA (Content Management API): Returns draft records with full CRUD operations
- CPA (Content Preview API): Returns draft records (read-only)
// Get published records (CDA)
const records = await client.cda.from('blog-posts')
.where('status', 'eq', 'published')
.and('category', 'eq', 'technology')
.orderBy('created_at', 'desc')
.page(1)
.pageSize(10)
.get();
// Access results
records.data.forEach(record => {
console.log(record.data.title);
});
// Pagination info
console.log('Total:', records.pagination.total);
console.log('Page:', records.pagination.page, 'of', records.pagination.page_count);
// Create a record (CMA only)
const newRecord = await client.cma.from('blog-posts')
.save({
data: {
title: 'My Blog Post',
content: 'Post content here'
}
});
// Update a record (CMA only)
await client.cma.from('blog-posts')
.id('record-id')
.save({
data: { title: 'Updated Title' }
});
// Delete a record (CMA only)
await client.cma.from('blog-posts')
.id('record-id')
.delete();
// Advanced filtering with grouping
const records = await client.cda.from('articles')
.where('status', 'eq', 'published')
.andOpenGrouping()
.where('featured', 'eq', true)
.or('views', 'gt', 1000)
.closeGrouping()
.get();
// Field selection
const records = await client.cda.from('articles')
.select('title', 'summary', 'author')
.get();
// Filter by tags
const records = await client.cda.from('articles')
.tags('featured', 'technology')
.where('status', 'eq', 'published')
.get();
// Aggregations
const stats = await client.cda.from('articles')
.where('status', 'eq', 'published')
.count()
.sum('views')
.avg('rating')
.get();
// Aggregations with grouping
const categoryStats = await client.cda.from('articles')
.groupBy('category', 'author')
.where('status', 'eq', 'published')
.count()
.sum('views')
.get();
// Results will be grouped by category and author
categoryStats.data.forEach(group => {
console.log(`Category: ${group.category}, Author: ${group.author}`);
console.log(`Count: ${group.count}`);
console.log(`Total views: ${group.views_sum}`);
});
File Manager
// Upload a file
const file = await client.files.upload({
file: fileBuffer,
filename: 'document.pdf',
path: 'documents/'
});
// List files
const files = await client.files.list({
path: 'documents/'
});
// Delete a file
await client.files.delete('documents/document.pdf');
Files
// Upload a file
const file = await client.files.upload({
file: fileBuffer,
filename: 'document.pdf',
path: 'documents/'
});
// List files
const files = await client.files.list({
path: 'documents/'
});
// Delete a file
await client.files.delete('documents/document.pdf');
Images
// Analyze an image
const analysis = await client.images.analyze({
imageUrl: 'https://example.com/image.jpg',
prompt: 'Describe this image'
});
// Generate an image
const image = await client.images.generate({
prompt: 'A sunset over mountains'
});
Scenarios
// List scenarios
const scenarios = await client.scenarios.list();
// Get a scenario
const scenario = await client.scenarios.get('scenario-id');
// Execute a scenario (uses method since it requires scenarioId)
const result = await client.scenario('scenario-id').execute({
input: 'Process this data'
});
Sites
// List sites
const sites = await client.sites.list();
// Get a site
const site = await client.sites.get('site-id');
// List pages for a site
const pages = await client.sites.pages('site-id').list();
// Get a page
const page = await client.sites.pages('site-id').get('page-id');
Other Collections
// Schedules
const schedules = await client.schedules.list();
const schedule = await client.schedules.get('schedule-id');
// Webhooks
const webhooks = await client.webhooks.list();
const webhook = await client.webhooks.get('webhook-id');
// Apps
const apps = await client.apps.list();
const app = await client.apps.get('app-id');
// MCP Servers
const servers = await client.mcpServers.list();
const server = await client.mcpServers.get('server-id');
// API Keys
const keys = await client.apikeys.list();
const key = await client.apikeys.get('key-id');
// Page Types
const pageTypes = await client.pageTypes.list();
const pageType = await client.pageTypes.get('page-type-id');
// Component Libraries
const libs = await client.libs.list();
const lib = await client.libs.get('lib-id');
Endpoints
Agents
Agents are AI-powered assistants that can be accessed through the Agents section. They support chat completions, multi-turn conversations, and file attachments.
Attachments
Delete an Attachment
DELETE /agents/{agentId}/chat/completion/workspace/{chatId}/messages/{messageId}/attachments/{filename}
Deletes a specific attachment from a message.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)messageId- The unique identifier of the message (string, required)filename- The name of the file to delete (string, required)
Responses:
200 OK- File deleted successfully204 No Content- For CORS preflight requests
Upload an Attachment
File uploads use a two-step process for security and efficiency:
Step 1: Get Upload URL
POST /agent/{agentId}/upload-url
Gets a signed upload URL for secure file upload.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema:
{
"filename": "example.pdf",
"contentType": "application/pdf",
"messageId": "msg_123456789",
"chatId": "chat_987654321"
}
Properties:
filename- The name of the file to upload (string, required)contentType- The MIME type of the file (string, optional)messageId- The unique identifier of the message (string, required)chatId- The unique identifier of the chat (string, required)
Responses:
200 OK- Returns upload URL and file information
{
"uploadUrl": "https://supabase-storage-url.com/signed-upload-url",
"fileUrl": "https://attachments.brightsy.ai/account/agents/agent-id/chats/chat-id/messages/message-id/filename.pdf",
"path": "account/agents/agent-id/chats/chat-id/messages/message-id/filename.pdf"
}
Step 2: Upload File to Signed URL
PUT {uploadUrl}
Upload the file directly to the signed URL returned from Step 1.
Request Body:
- Content Type: The content type specified in Step 1
- Body: Raw file binary data
Responses:
200 OK- File uploaded successfully
Complete Upload Example:
// Step 1: Get upload URL
const uploadResponse = await fetch('/api/v1beta/agent/agent-123/upload-url', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
filename: 'document.pdf',
contentType: 'application/pdf',
messageId: 'msg-456',
chatId: 'chat-789'
})
});
const { uploadUrl, fileUrl } = await uploadResponse.json();
// Step 2: Upload file to signed URL
const fileUploadResponse = await fetch(uploadUrl, {
method: 'PUT',
headers: {
'Content-Type': 'application/pdf'
},
body: fileBuffer
});
// File is now accessible at fileUrl
Messages
Create or Update Message
POST /agent/{agentId}/chat/completion/workspace/{chatId}/message/{messageId}
Creates or updates a message within a chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)messageId- The unique identifier of the message (string, required)
Request Body:
- Content Type:
application/json - Schema: A Message object
Responses:
200 OK- Message created/updated successfully
Delete Message
DELETE /agent/{agentId}/chat/completion/workspace/{chatId}/message/{messageId}
Deletes a specific message.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)messageId- The unique identifier of the message (string, required)
Responses:
200 OK- Message deleted successfully204 No Content- For CORS preflight requests
List Messages
GET /agent/{agentId}/chat/completion/workspace/{chatId}/message
Retrieves a list of messages within a chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Responses:
200 OK- Returns a list of messages
Add Message to Chat
POST /agent/{agentId}/chat/completion/workspace/{chatId}/message
Creates a new message within a chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Request Body:
- Content Type:
application/json - Schema: A Message object
Responses:
200 OK- Message created successfully204 No Content- For CORS preflight requests
Chats
Get Chat Details
GET /agent/{agentId}/chat/completion/workspace/{chatId}/message
Retrieves details of a specific chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Responses:
200 OK- Returns chat details
Create Chat
POST /agent/{agentId}/chat/completion/workspace/{chatId}/message
Creates a new message and chat if needed.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Request Body:
- Content Type:
application/json - Schema: An object containing a
messageproperty of type string
Responses:
200 OK- Chat created successfully204 No Content- For CORS preflight requests
Agent Messages
Create Workspace Chat
POST /agent/{agentId}/chat/completion/workspace
Creates a message for an agent and starts a new workspace-based chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema: A Message object
Responses:
200 OK- Message created successfully204 No Content- For CORS preflight requests
Create Completion
POST /agents/{agentId}/chat/completion
Creates a completion where the client provides the entire messages array.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema:
{
"messages": [
{
"role": "system",
"content": "Additional context: The user is asking about enterprise pricing."
},
{
"role": "user",
"content": "Hello, how can you help me?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name"
}
},
"required": ["location"]
}
}
}
],
"max_tokens": 16000
}
Properties:
messages- Array of message objects withrole(system,user,assistant, ortool) andcontent(array, required). Note: Agents have their primary system prompt saved in their definition. System messages here are appended to provide additional context.tools- Array of function tools the agent can call (array, optional)max_tokens- Maximum tokens for the response, overrides agent default (number, optional)
Responses:
200 OK- Completion generated successfully204 No Content- For CORS preflight requests
Note: This endpoint does not store the conversation in Brightsy. No chatId is used as the conversation is managed by the client.
Cancel Chat Completion
POST /agent/{agentId}/chat/completion/cancel
Cancels an ongoing chat completion request.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema:
{
"request_id": "req_123456789",
"chat_id": "chat_987654321",
"reason": "user_cancellation"
}
Properties:
request_id- The unique identifier of the request to cancel (string, required)chat_id- The unique identifier of the chat (string, optional - only needed for workspace-based chats)reason- The reason for cancellation (string, optional, defaults to "user_cancellation")
Responses:
200 OK- Request cancelled successfully
{
"message": "Request cancelled successfully",
"cancelled_at": "2024-01-15T10:30:00.000Z",
"request_id": "req_123456789"
}
400 Bad Request- Invalid request parameters401 Unauthorized- User does not have access to agent404 Not Found- Agent not found
Error Responses:
{
"error": {
"message": "request_id is required"
}
}
Note: If a request has already been cancelled, the endpoint will return a 200 status with the message "Request already cancelled".
A2A Protocol (Agent-to-Agent)
The A2A protocol enables Brightsy agents to communicate with other agents, both within Brightsy and across external platforms. For complete documentation, see the A2A Protocol Guide.
Agent Card Discovery
Get Agent Card
GET /agent/{agentId}/a2a/card
Returns the agent's A2A card describing its capabilities, skills, and endpoint.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Responses:
200 OK- Returns the A2A agent card
{
"id": "agent-id",
"name": "Weather Agent",
"description": "Provides weather information",
"endpoint": "https://brightsy.ai/api/v1beta/agent/agent-id/a2a",
"skills": [
{
"name": "current_weather",
"description": "Get current weather for a location"
}
],
"auth": {
"type": "bearer",
"config": {
"required": true,
"description": "OAuth 2.1 access token or API key"
}
},
"security": [
{
"schemes": {
"bearer_auth": { "list": [] },
"oauth2": { "list": [] }
}
}
],
"securitySchemes": {
"bearer_auth": {
"httpAuthSecurityScheme": {
"scheme": "Bearer",
"bearerFormat": "JWT",
"description": "Use OAuth 2.1 access token or Brightsy API key"
}
},
"oauth2": {
"oauth2SecurityScheme": {
"description": "OAuth 2.1 Authorization Code flow with PKCE",
"flows": {
"authorizationCode": {
"authorizationUrl": "https://brightsy.ai/oauth/authorize",
"tokenUrl": "https://brightsy.ai/oauth/token",
"refreshUrl": "https://brightsy.ai/oauth/token",
"scopes": {
"brightsy:api": "Access to Brightsy agent APIs"
}
}
},
"oauth2MetadataUrl": "https://brightsy.ai/.well-known/oauth-authorization-server"
}
}
},
"capabilities": [
{ "type": "streaming", "supported": true },
{ "type": "multi-turn", "supported": true }
]
}
Authentication: None required (public discovery endpoint)
Notes:
- External agents use this endpoint to discover your agent's capabilities
- The
securitySchemessection shows all supported authentication methods - OAuth metadata URL provides automatic configuration for OAuth clients
Task Management
Create Task
POST /agent/{agentId}/a2a/tasks
Creates a new A2A task (conversation).
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
{
"message": {
"role": "user",
"content": [
{ "type": "text", "text": "Hello!" }
]
}
}
Responses:
201 Created- Task created, returns task with running status and stream endpoint
Get Task Status
GET /agent/{agentId}/a2a/tasks/{taskId}
Gets the current status of an A2A task (polling).
Path Parameters:
agentId- The unique identifier of the agent (string, required)taskId- The unique identifier of the task (string, required)
Responses:
200 OK- Returns task with current status and messages
Stream Task Updates
GET /agent/{agentId}/a2a/tasks/{taskId}/stream
Streams real-time updates for an A2A task via Server-Sent Events (SSE).
Path Parameters:
agentId- The unique identifier of the agent (string, required)taskId- The unique identifier of the task (string, required)
Request Headers:
Accept: text/event-stream
Responses:
200 OK- Returns SSE stream with task updates
Event Format:
data: {"result":{"task":{...},"final":false}}
data: {"result":{"task":{...},"final":true}}
Append Message (Multi-Turn)
POST /agent/{agentId}/a2a/tasks/{taskId}
Appends a message to an existing task for multi-turn conversations.
Path Parameters:
agentId- The unique identifier of the agent (string, required)taskId- The unique identifier of the task (string, required)
Request Body:
{
"message": {
"role": "user",
"content": [
{ "type": "text", "text": "Follow-up question" }
]
}
}
Responses:
200 OK- Message appended, task updated
Cancel Task
DELETE /agent/{agentId}/a2a/tasks/{taskId}
Cancels an ongoing A2A task.
Path Parameters:
agentId- The unique identifier of the agent (string, required)taskId- The unique identifier of the task (string, required)
Responses:
200 OK- Task cancelled successfully
External Connections
Connect to External Agent
POST /agent/{agentId}/external-a2a-connections
Connects to an external A2A-compliant agent.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
{
"endpoint": "https://external-agent.com/a2a",
"auth_config": {
"type": "bearer",
"token": "xyz"
}
}
Responses:
200 OK- Connection created successfully
List External Connections
GET /agent/{agentId}/external-a2a-connections
Lists all external A2A agent connections.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Responses:
200 OK- Returns array of external connections
Remove External Connection
DELETE /agent/{agentId}/external-a2a-connections/{externalAgentId}
Removes a connection to an external A2A agent.
Path Parameters:
agentId- The unique identifier of the agent (string, required)externalAgentId- The unique identifier of the external agent (string, required)
Responses:
200 OK- Connection removed successfully
CMS (Content Management System)
The CMS allows you to manage structured content with custom record types, relationships, and localization. Access the CMS through the CMS section.
Record Types
Record types define the structure of your content. They can be created and managed through the CMS interface.
Records
The BrightsyClient provides a fluent API for querying CMS records with three endpoints:
API Endpoints:
client.cda- Content Delivery API (read-only published records)client.cma- Content Management API (full CRUD on draft records)client.cpa- Content Preview API (read-only latest draft version)
Query Methods:
.from(slug)- Specify record type by slug (alias:.recordType(slug)).where(field, operator, value)- Add filter condition.and(field, operator, value)- Add AND filter condition.or(field, operator, value)- Add OR filter condition.openGrouping()- Open parenthesis for filter grouping.andOpenGrouping()- AND with opening parenthesis.orOpenGrouping()- OR with opening parenthesis.closeGrouping()- Close parenthesis.select(...fields)- Select specific fields to return.groupBy(...fields)- Alias for select, used with aggregates for grouping.orderBy(field, direction)- Sort results ('asc' or 'desc').page(number)- Set page number.pageSize(size)- Set page size.count(field?)- Add count aggregate.sum(field)- Add sum aggregate.avg(field)- Add average aggregate.min(field)- Add min aggregate.max(field)- Add max aggregate.tags(...tagNames)- Filter by tags.id(id)- Specify record ID for single record operations
Filter Operators:
eq- Equalsneq- Not equalsgt- Greater thangte- Greater than or equallt- Less thanlte- Less than or equallike- Contains (case-sensitive)ilike- Contains (case-insensitive)in- In arraynotIn- Not in arraybegins- Begins withends- Ends with
// Query published records
const records = await client.cda.from('articles')
.where('status', 'eq', 'published')
.and('category', 'eq', 'technology')
.orderBy('published_at', 'desc')
.get();
// Access results
records.data.forEach(record => {
console.log(record.data);
});
// Pagination
console.log(records.pagination.total); // Total count
console.log(records.pagination.page); // Current page
console.log(records.pagination.page_count); // Total pages
console.log(records.pagination.page_size); // Page size
// Complex filtering with grouping
// Query: status = 'published' AND (featured = true OR views > 1000)
const records = await client.cda.from('articles')
.where('status', 'eq', 'published')
.andOpenGrouping()
.where('featured', 'eq', true)
.or('views', 'gt', 1000)
.closeGrouping()
.get();
// Field selection
const records = await client.cda.from('articles')
.select('title', 'summary', 'author.name')
.where('status', 'eq', 'published')
.get();
// Filter by tags
const records = await client.cda.from('articles')
.tags('featured', 'technology')
.where('status', 'eq', 'published')
.get();
// Create record (CMA only)
await client.cma.from('articles').save({
data: {
title: 'New Article',
content: 'Article content'
},
tags: ['featured', 'technology']
});
// Update record (CMA only)
await client.cma.from('articles').id('record-id').save({
data: { title: 'Updated Title' }
});
// Delete record (CMA only)
await client.cma.from('articles').id('record-id').delete();
// Aggregations
const stats = await client.cda.from('articles')
.where('status', 'eq', 'published')
.count()
.sum('views')
.avg('rating')
.get();
// Aggregations with grouping by category
const categoryStats = await client.cda.from('articles')
.groupBy('category', 'author')
.where('status', 'eq', 'published')
.count()
.sum('views')
.get();
// Results will be grouped by category and author
categoryStats.data.forEach(group => {
console.log(`Category: ${group.category}, Author: ${group.author}`);
console.log(`Count: ${group.count}`);
console.log(`Total views: ${group.views_sum}`);
});
File Manager
The File Manager provides storage and organization for files. Access it through the File Manager section in the main navigation.
Upload Files
const file = await client.files.upload({
file: fileBuffer,
filename: 'document.pdf',
path: 'documents/'
});
List Files
const files = await client.files.list({
path: 'documents/',
limit: 50
});
Delete Files
await client.files.delete('documents/document.pdf');
Automations
The Automations section provides tools for workflow automation, including scenarios, API keys, webhooks, and schedules.
Scenarios
Scenarios are automated workflows that can be triggered by webhooks or scheduled executions.
Execute Scenario
POST /scenario/{scenarioId}
Executes a scenario.
Path Parameters:
scenarioId- The unique identifier of the scenario (string, required)
Request Headers:
[Signature Header Name]- The header name is defined in the scenario configuration assignature_name. For example, ifsignature_nameis set to "X-Scenario-Signature", you would include that header in your request. While you could technically use the rawsignature_secretas the header value, it's best practice to generate a signature using thesignature_secretand the payload as described below.
Signature Generation:
The signature must be generated using HMAC SHA-256 with the following process:
- Convert the entire request body to a JSON string (payload)
- Create an HMAC SHA-256 hash using the scenario's
signature_secretas the key - Update the hash with the payload string directly
- Get the hex digest of the hash, which becomes the signature value
Example (Node.js):
const crypto = require('crypto');
const payload = JSON.stringify(requestBody);
const signature = crypto.createHmac('sha256', signature_secret)
.update(payload, 'utf8')
.digest('hex');
Security Best Practice: Using HMAC signatures as shown above is the recommended best practice for API security. The signature validates the authenticity of requests and ensures data integrity, protecting against tampering. Store your signature_secret securely and never expose it in client-side code.
Request Body:
- Content Type:
application/json - Schema: An object containing an
inputproperty of type string
Responses:
200 OK- Scenario executed successfully401 Unauthorized- When the signature header is missing or invalid204 No Content- For CORS preflight requests
API Keys
API keys are managed in Automations → API Keys. They can be scoped to specific agents, scenarios, or CMS access.
Webhooks
Webhooks are managed in Automations → Webhooks. They allow external systems to trigger scenarios or receive notifications.
Schedules
Scheduled executions can be configured in Automations → Schedules to run scenarios at specific times or intervals.
Object Models
Message Object
Represents a message with various content types.
Properties:
id- Unique identifier for the message (string)role- The role of the message author. One of:system- Additional context or instructions to supplement the agent's built-in system promptuser- Messages from the userassistant- Messages from the AI assistanttool- Tool/function call results
content- Array of content items, each being one of:- Text: Object with
typeas "text" andtextas a string - Image URL: Object with
typeas "image_url" andimage_urlcontainingurland optionaldetail
- Text: Object with
Note: Brightsy agents have their primary system prompt configured in the agent definition. When you include system role messages in API requests, they are appended to the agent's existing system prompt to provide additional context for that specific request.
Example:
{
"id": "msg_123456789",
"role": "user",
"content": [
{
"type": "text",
"text": "Hello, this is a text message"
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.jpg",
"detail": "high"
}
}
]
}
System Message Example (adds context to the agent's built-in prompt):
{
"id": "msg_system_001",
"role": "system",
"content": [
{
"type": "text",
"text": "The user is currently viewing the checkout page and has items in their cart."
}
]
}
Chat Object
Represents a chat containing messages.
Properties:
id- Unique identifier for the chat (string)messages- Array of Message objects
Example:
{
"id": "chat_987654321",
"messages": [
{
"id": "msg_123456789",
"content": [
{
"type": "text",
"text": "Hello, this is a text message"
}
]
}
]
}
Attachments
Delete an Attachment
DELETE /agents/{agentId}/chat/completion/workspace/{chatId}/messages/{messageId}/attachments/{filename}
Deletes a specific attachment from a message.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)messageId- The unique identifier of the message (string, required)filename- The name of the file to delete (string, required)
Responses:
200 OK- File deleted successfully204 No Content- For CORS preflight requests
Upload an Attachment
File uploads use a two-step process for security and efficiency:
Step 1: Get Upload URL
POST /agent/{agentId}/upload-url
Gets a signed upload URL for secure file upload.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema:
{
"filename": "example.pdf",
"contentType": "application/pdf",
"messageId": "msg_123456789",
"chatId": "chat_987654321"
}
Properties:
filename- The name of the file to upload (string, required)contentType- The MIME type of the file (string, optional)messageId- The unique identifier of the message (string, required)chatId- The unique identifier of the chat (string, required)
Responses:
200 OK- Returns upload URL and file information
{
"uploadUrl": "https://supabase-storage-url.com/signed-upload-url",
"fileUrl": "https://attachments.brightsy.ai/account/agents/agent-id/chats/chat-id/messages/message-id/filename.pdf",
"path": "account/agents/agent-id/chats/chat-id/messages/message-id/filename.pdf"
}
Step 2: Upload File to Signed URL
PUT {uploadUrl}
Upload the file directly to the signed URL returned from Step 1.
Request Body:
- Content Type: The content type specified in Step 1
- Body: Raw file binary data
Responses:
200 OK- File uploaded successfully
Complete Upload Example:
// Step 1: Get upload URL
const uploadResponse = await fetch('/api/v1beta/agent/agent-123/upload-url', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
filename: 'document.pdf',
contentType: 'application/pdf',
messageId: 'msg-456',
chatId: 'chat-789'
})
});
const { uploadUrl, fileUrl } = await uploadResponse.json();
// Step 2: Upload file to signed URL
const fileUploadResponse = await fetch(uploadUrl, {
method: 'PUT',
headers: {
'Content-Type': 'application/pdf'
},
body: fileBuffer
});
// File is now accessible at fileUrl
Messages
Create or Update Message
POST /agent/{agentId}/chat/completion/workspace/{chatId}/message/{messageId}
Creates or updates a message within a chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)messageId- The unique identifier of the message (string, required)
Request Body:
- Content Type:
application/json - Schema: A Message object
Responses:
200 OK- Message created/updated successfully
Delete Message
DELETE /agent/{agentId}/chat/completion/workspace/{chatId}/message/{messageId}
Deletes a specific message.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)messageId- The unique identifier of the message (string, required)
Responses:
200 OK- Message deleted successfully204 No Content- For CORS preflight requests
List Messages
GET /agent/{agentId}/chat/completion/workspace/{chatId}/message
Retrieves a list of messages within a chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Responses:
200 OK- Returns a list of messages
Add Message to Chat
POST /agent/{agentId}/chat/completion/workspace/{chatId}/message
Creates a new message within a chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Request Body:
- Content Type:
application/json - Schema: A Message object
Responses:
200 OK- Message created successfully204 No Content- For CORS preflight requests
Chats
Get Chat Details
GET /agent/{agentId}/chat/completion/workspace/{chatId}/message
Retrieves details of a specific chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Responses:
200 OK- Returns chat details
Create Chat
POST /agent/{agentId}/chat/completion/workspace/{chatId}/message
Creates a new message and chat if needed.
Path Parameters:
agentId- The unique identifier of the agent (string, required)chatId- The unique identifier of the chat (string, required)
Request Body:
- Content Type:
application/json - Schema: An object containing a
messageproperty of type string
Responses:
200 OK- Chat created successfully204 No Content- For CORS preflight requests
Agent Messages
Create Workspace Chat
POST /agent/{agentId}/chat/completion/workspace
Creates a message for an agent and starts a new workspace-based chat.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema: A Message object
Responses:
200 OK- Message created successfully204 No Content- For CORS preflight requests
Create Completion
POST /agents/{agentId}/chat/completion
Creates a completion where the client provides the entire messages array.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema:
{
"messages": [
{
"role": "system",
"content": "Additional context: The user is asking about enterprise pricing."
},
{
"role": "user",
"content": "Hello, how can you help me?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name"
}
},
"required": ["location"]
}
}
}
],
"max_tokens": 16000
}
Properties:
messages- Array of message objects withrole(system,user,assistant, ortool) andcontent(array, required). Note: Agents have their primary system prompt saved in their definition. System messages here are appended to provide additional context.tools- Array of function tools the agent can call (array, optional)max_tokens- Maximum tokens for the response, overrides agent default (number, optional)
Responses:
200 OK- Completion generated successfully204 No Content- For CORS preflight requests
Note: This endpoint does not store the conversation in Brightsy. No chatId is used as the conversation is managed by the client.
Cancel Chat Completion
POST /agent/{agentId}/chat/completion/cancel
Cancels an ongoing chat completion request.
Path Parameters:
agentId- The unique identifier of the agent (string, required)
Request Body:
- Content Type:
application/json - Schema:
{
"request_id": "req_123456789",
"chat_id": "chat_987654321",
"reason": "user_cancellation"
}
Properties:
request_id- The unique identifier of the request to cancel (string, required)chat_id- The unique identifier of the chat (string, optional - only needed for workspace-based chats)reason- The reason for cancellation (string, optional, defaults to "user_cancellation")
Responses:
200 OK- Request cancelled successfully
{
"message": "Request cancelled successfully",
"cancelled_at": "2024-01-15T10:30:00.000Z",
"request_id": "req_123456789"
}
400 Bad Request- Invalid request parameters401 Unauthorized- User does not have access to agent404 Not Found- Agent not found
Error Responses:
{
"error": {
"message": "request_id is required"
}
}
Note: If a request has already been cancelled, the endpoint will return a 200 status with the message "Request already cancelled".
Scenarios
Execute Scenario
POST /scenario/{scenarioId}
Executes a scenario.
Path Parameters:
scenarioId- The unique identifier of the scenario (string, required)
Request Headers:
[Signature Header Name]- The header name is defined in the scenario configuration assignature_name. For example, ifsignature_nameis set to "X-Scenario-Signature", you would include that header in your request. While you could technically use the rawsignature_secretas the header value, it's best practice to generate a signature using thesignature_secretand the payload as described below.
Signature Generation:
The signature must be generated using HMAC SHA-256 with the following process:
- Convert the entire request body to a JSON string (payload)
- Create an HMAC SHA-256 hash using the scenario's
signature_secretas the key - Update the hash with the payload string directly
- Get the hex digest of the hash, which becomes the signature value
Example (Node.js):
const crypto = require('crypto');
const payload = JSON.stringify(requestBody);
const signature = crypto.createHmac('sha256', signature_secret)
.update(payload, 'utf8')
.digest('hex');
Security Best Practice: Using HMAC signatures as shown above is the recommended best practice for API security. The signature validates the authenticity of requests and ensures data integrity, protecting against tampering. Store your signature_secret securely and never expose it in client-side code.
Request Body:
- Content Type:
application/json - Schema: An object containing an
inputproperty of type string
Responses:
200 OK- Scenario executed successfully401 Unauthorized- When the signature header is missing or invalid204 No Content- For CORS preflight requests
Object Models
Message Object
Represents a message with various content types.
Properties:
id- Unique identifier for the message (string)role- The role of the message author. One of:system- Additional context or instructions to supplement the agent's built-in system promptuser- Messages from the userassistant- Messages from the AI assistanttool- Tool/function call results
content- Array of content items, each being one of:- Text: Object with
typeas "text" andtextas a string - Image URL: Object with
typeas "image_url" andimage_urlcontainingurland optionaldetail
- Text: Object with
Note: Brightsy agents have their primary system prompt configured in the agent definition. When you include system role messages in API requests, they are appended to the agent's existing system prompt to provide additional context for that specific request.
Example:
{
"id": "msg_123456789",
"role": "user",
"content": [
{
"type": "text",
"text": "Hello, this is a text message"
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.jpg",
"detail": "high"
}
}
]
}
System Message Example (adds context to the agent's built-in prompt):
{
"id": "msg_system_001",
"role": "system",
"content": [
{
"type": "text",
"text": "The user is currently viewing the checkout page and has items in their cart."
}
]
}
Chat Object
Represents a chat containing messages.
Properties:
id- Unique identifier for the chat (string)messages- Array of Message objects
Example:
{
"id": "chat_987654321",
"messages": [
{
"id": "msg_123456789",
"content": [
{
"type": "text",
"text": "Hello, this is a text message"
}
]
}
]
}