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:
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();
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 format
formatMessages(messages) - Converts Brightsy format messages to Vercel AI SDK format with parts for rendering
generateUUID() - 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:
formatMessages merges consecutive messages of the same role and tool/assistant messages
Tool calls and their results are combined into single tool-invocation parts with state: '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:
client.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 using formatMessages().
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:
// 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');
Agents are AI-powered assistants that can be accessed through the Agents section. They support chat completions, multi-turn conversations, and file attachments.
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 with role (system, user, assistant, or tool) and content (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 successfully
204 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)
401 Unauthorized - User does not have access to agent
404 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)
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 as signature_name. For example, if signature_name is set to "X-Scenario-Signature", you would include that header in your request. While you could technically use the raw signature_secret as the header value, it's best practice to generate a signature using the signature_secret and 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_secret as the key
Update the hash with the payload string directly
Get the hex digest of the hash, which becomes the signature value
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 input property of type string
Responses:
200 OK - Scenario executed successfully
401 Unauthorized - When the signature header is missing or invalid
204 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 prompt
user - Messages from the user
assistant - Messages from the AI assistant
tool - Tool/function call results
content - Array of content items, each being one of:
Text: Object with type as "text" and text as a string
Image URL: Object with type as "image_url" and image_url containing url and optional detail
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."
}
]
}
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 with role (system, user, assistant, or tool) and content (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 successfully
204 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)
401 Unauthorized - User does not have access to agent
404 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 as signature_name. For example, if signature_name is set to "X-Scenario-Signature", you would include that header in your request. While you could technically use the raw signature_secret as the header value, it's best practice to generate a signature using the signature_secret and 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_secret as the key
Update the hash with the payload string directly
Get the hex digest of the hash, which becomes the signature value
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 input property of type string
Responses:
200 OK - Scenario executed successfully
401 Unauthorized - When the signature header is missing or invalid
204 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 prompt
user - Messages from the user
assistant - Messages from the AI assistant
tool - Tool/function call results
content - Array of content items, each being one of:
Text: Object with type as "text" and text as a string
Image URL: Object with type as "image_url" and image_url containing url and optional detail
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."
}
]
}