The CEO.ai SDK is a lightweight Node.js client with zero external dependencies. Send prompts, manage conversations, train agents with RAG memory, and poll for results — all from your application code. Built on Node.js built-in modules. Nothing extra to install.
const { CeoAI } = require('@ceo-ai/sdk');
const ceo = new CeoAI({ apiKey: 'sk_live_your_api_key_here' });
// Send a prompt and wait for the result
const { response, metadata } = await ceo.promptAndWait('What was our Q4 revenue?');
console.log(response);
// => { answer: "Q4 revenue was $12.5M, representing a 15% increase..." }
Lightweight by design. No bloat, no surprises, no dependency hell.
Add intelligent responses, data processing, or content generation to any Express/Fastify/Koa app
Slack bots, Telegram bots, Discord bots, WhatsApp bots — all backed by your trained agents
Batch process documents, analyze data, generate reports on a schedule
Build AI-powered SaaS features with your agents as the intelligence layer
Connect your agents to any system that runs Node.js
Dashboards, admin panels, and scripts that leverage your AI agents
$ npm install @ceo-ai/sdk
That's it. No peer dependencies. No additional installs.
Log in to the CEO.ai Dashboard
Navigate to API Keys
Click Create API Key (requires a paid subscription)
Select the agent you want this key to connect to
Copy the generated key — it's only shown once
const { CeoAI } = require('@ceo-ai/sdk');
const ceo = new CeoAI({
apiKey: 'sk_live_...', // Required
endpoint: 'https://...', // Optional. Default: 'https://ingestion.api.ceo.ai'
timeout: 30000, // Optional. Request timeout in ms. Default: 30000
pollInterval: 2000, // Optional. Default polling interval in ms. Default: 2000
pollTimeout: 120000 // Optional. Default polling timeout in ms. Default: 120000
});
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| apiKey | string | ✅ | — | Your API key (sk_live_...) |
| endpoint | string | — | https://ingestion.api.ceo.ai | API endpoint URL |
| timeout | number | — | 30000 | HTTP request timeout in ms |
| pollInterval | number | — | 2000 | Default interval between poll attempts in ms |
| pollTimeout | number | — | 120000 | Default max time to wait when polling in ms |
Best practice
Store your API key in an environment variable, not in code:
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
Send a prompt to your AI agent. Returns immediately with a presigned URL.
This is the low-level method. It submits the prompt and returns right away — the actual AI processing happens asynchronously. Use this when you want to control the polling yourself, or when you're building a fire-and-forget architecture.
const result = await ceo.prompt('What was our Q4 revenue?');
console.log(result);
// {
// presignedUrl: 'https://ceo-ai-api-output-results.s3.amazonaws.com/...',
// message: 'Processing request',
// estimatedCredits: 10,
// agentId: 'abc-123',
// agentName: 'Financial Analyst',
// model: 'claude-sonnet-4-5',
// tenantId: 'tenant-456'
// }
| Parameter | Type | Required | Description |
|---|---|---|---|
| prompt | string | ✅ | The prompt text to send |
| options.ragMode | boolean | — | Enable/disable RAG. Default: true (server-side) |
| options.conversationHistory | Array | — | Previous messages for context |
Returns: Promise<PromptResponse>
Send a prompt and automatically poll until the result is ready.
This is the most convenient method for typical usage. It handles the entire async flow — submit the prompt, poll for results, and return them when ready.
const { response, metadata } = await ceo.promptAndWait('What was our Q4 revenue?', {
pollInterval: 3000,
pollTimeout: 60000,
onPoll: (attempt, elapsed) => {
console.log(`Waiting... attempt ${attempt} (${elapsed}ms)`);
}
});
console.log(response); // The AI response
console.log(metadata); // Agent/model/credits info
| Parameter | Type | Required | Description |
|---|---|---|---|
| prompt | string | ✅ | The prompt text to send |
| options.ragMode | boolean | — | Enable/disable RAG |
| options.conversationHistory | Array | — | Previous messages for context |
| options.pollInterval | number | — | Override polling interval in ms |
| options.pollTimeout | number | — | Override polling timeout in ms |
| options.onPoll | Function | — | Callback: (attempt, elapsed) => {} |
Returns: Promise<{ response: any, metadata: Object }>
Poll a presigned URL until content is available.
Use this when you've stored a presigned URL from a previous prompt() call and want to check for results later — even in a different process or at a different time.
const result = await ceo.pollForResult(presignedUrl, {
interval: 3000,
timeout: 60000,
onPoll: (attempt, elapsed) => {
console.log(`Attempt ${attempt} (${elapsed}ms elapsed)`);
}
});
| Parameter | Type | Required | Description |
|---|---|---|---|
| presignedUrl | string | ✅ | The presigned URL to poll |
| options.interval | number | — | Polling interval in ms |
| options.timeout | number | — | Max wait time in ms |
| options.onPoll | Function | — | Callback: (attempt, elapsed) => {} |
Returns: Promise<Object | string> — Parsed JSON if possible, raw string otherwise.
Add file content as RAG memory to your agent.
This is how you programmatically train your agents. Pass in file content and a filename — the SDK handles chunking and category detection automatically. The agent can then use this knowledge when responding to prompts.
const fs = require('fs');
const content = fs.readFileSync('./docs/product-guide.md', 'utf8');
const result = await ceo.addRag(content, 'product-guide.md');
console.log(result);
// {
// success: true,
// filename: 'product-guide.md',
// category: 'documentation',
// totalChunks: 5,
// contentLength: 8420,
// memoriesAdded: 5,
// creditsDeducted: 2150,
// agentId: 'agent-123',
// tenantId: 'tenant-456'
// }
| Parameter | Type | Required | Description |
|---|---|---|---|
| content | string | ✅ | The file content to add |
| filename | string | ✅ | Filename (used for auto category detection) |
| options.category | string | — | Override auto-detected category: code, documentation, data, other |
| options.chunkSize | number | — | Max chunk size in characters. Default: 2000 |
Returns: Promise<AddRagResponse>
| Category | Extensions |
|---|---|
| code | .js, .ts, .py, .java, .go, .rs, .sql, .sh, .json, .yaml, .html, .css, and more |
| documentation | .md, .txt, .rst, .pdf, .doc, .docx |
| data | .csv, .tsv, .log |
Custom error class thrown for API errors.
Includes convenience getters so you can handle specific error types cleanly — without parsing error messages or status codes manually.
const { CeoAI, CeoAPIError } = require('@ceo-ai/sdk');
try {
await ceo.promptAndWait('Hello');
} catch (error) {
if (error instanceof CeoAPIError) {
console.log(error.message); // Error message
console.log(error.statusCode); // HTTP status code
console.log(error.details); // Additional details (if any)
// Convenience getters
error.isAuthError; // true if 401
error.isInsufficientCredits; // true if 402
error.isRateLimited; // true if 429
error.isTimeout; // true if 408
}
}
Copy-paste patterns for the most common integration scenarios.
The most basic usage — send a prompt, get a response.
const { CeoAI } = require('@ceo-ai/sdk');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
const { response } = await ceo.promptAndWait('Summarize our sales this quarter');
console.log(response);
Submit a prompt and store the presigned URL. Retrieve results later — even from a different process.
Best for: Background processing, queue-based architectures, long-running tasks
const { CeoAI } = require('@ceo-ai/sdk');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
// Submit the prompt
const submission = await ceo.prompt('Generate a detailed report');
console.log('Presigned URL:', submission.presignedUrl);
// Store submission.presignedUrl in your database
// ...
// Later (even in a different process), retrieve the result:
const result = await ceo.pollForResult(storedPresignedUrl);
console.log(result);
Maintain context across multiple prompts. Pass the full conversation history so the agent understands the follow-up.
Best for: Chatbot interfaces, multi-turn analysis
const { CeoAI } = require('@ceo-ai/sdk');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
// First message
const first = await ceo.promptAndWait('What was our Q4 revenue?');
console.log(first.response);
// Follow-up with context
const second = await ceo.promptAndWait('How does that compare to Q3?', {
conversationHistory: [
{ role: 'user', content: 'What was our Q4 revenue?' },
{ role: 'assistant', content: JSON.stringify(first.response) }
]
});
console.log(second.response);
For prompts where you want the agent's base capabilities without retrieving from its trained knowledge.
const { response } = await ceo.promptAndWait('What is 2 + 2?', {
ragMode: false
});
Get visibility into the polling process with the onPoll callback.
Best for: CLI tools, admin dashboards, user-facing integrations
const { response } = await ceo.promptAndWait('Complex analysis...', {
pollInterval: 3000,
pollTimeout: 300000, // 5 minutes
onPoll: (attempt, elapsed) => {
const seconds = Math.round(elapsed / 1000);
console.log(`⏳ Waiting for response... ${seconds}s (attempt ${attempt})`);
}
});
Train your agent on your company's documents, code, and data — programmatically.
Best for: Automated knowledge pipelines, CI/CD integration, bulk ingestion
const { CeoAI } = require('@ceo-ai/sdk');
const fs = require('fs');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
// Train on a single document
const content = fs.readFileSync('./docs/product-guide.md', 'utf8');
const result = await ceo.addRag(content, 'product-guide.md');
console.log(`Added ${result.memoriesAdded} memories (${result.creditsDeducted} credits)`);
// Train on an entire directory of files
const path = require('path');
async function trainOnDirectory(dirPath) {
const files = fs.readdirSync(dirPath);
for (const file of files) {
const filePath = path.join(dirPath, file);
const stat = fs.statSync(filePath);
if (stat.isFile() && stat.size <= 4 * 1024 * 1024) { // Max 4MB
const content = fs.readFileSync(filePath, 'utf8');
const result = await ceo.addRag(content, file);
console.log(`✓ ${file} (${result.totalChunks} chunks, ${result.creditsDeducted} credits)`);
}
}
}
await trainOnDirectory('./knowledge-base');
Handle every error type cleanly with specific messaging for each case.
const { CeoAI, CeoAPIError } = require('@ceo-ai/sdk');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
try {
const { response } = await ceo.promptAndWait('What was our Q4 revenue?');
console.log(response);
} catch (error) {
if (error instanceof CeoAPIError) {
switch (true) {
case error.isAuthError:
console.error('❌ Invalid or expired API key');
console.error(' Get a new key at https://app.ceo.ai/apikeys');
break;
case error.isInsufficientCredits:
console.error('❌ Insufficient credits');
console.error(` Required: ${error.details?.requiredCredits}`);
console.error(` Available: ${error.details?.availableCredits}`);
console.error(' Add credits at https://app.ceo.ai/usercredits');
break;
case error.isTimeout:
console.error('❌ Request timed out');
console.error(' Try increasing pollTimeout');
break;
case error.isRateLimited:
console.error('❌ Rate limited. Please wait and try again.');
break;
default:
console.error(`❌ API error (${error.statusCode}): ${error.message}`);
}
} else {
console.error('❌ Unexpected error:', error.message);
}
}
Add AI-powered endpoints to any Express app — both async and synchronous patterns.
Best for: Adding AI features to existing web apps, building AI-powered APIs
const express = require('express');
const { CeoAI, CeoAPIError } = require('@ceo-ai/sdk');
const app = express();
app.use(express.json());
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
// Async endpoint — returns presigned URL immediately
// Client polls for results on their own
app.post('/api/ask', async (req, res) => {
try {
const result = await ceo.prompt(req.body.question);
res.json({
presignedUrl: result.presignedUrl,
estimatedCredits: result.estimatedCredits
});
} catch (error) {
if (error instanceof CeoAPIError) {
res.status(error.statusCode).json({ error: error.message });
} else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
// Sync endpoint — waits for result before responding
// Simpler for the client, but holds the connection open
app.post('/api/ask/sync', async (req, res) => {
try {
const { response, metadata } = await ceo.promptAndWait(req.body.question, {
pollTimeout: 60000
});
res.json({ response, metadata });
} catch (error) {
if (error instanceof CeoAPIError) {
res.status(error.statusCode).json({
error: error.message,
details: error.details
});
} else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
// RAG training endpoint — let authorized users train the agent
app.post('/api/train', async (req, res) => {
try {
const result = await ceo.addRag(req.body.content, req.body.filename, {
category: req.body.category
});
res.json(result);
} catch (error) {
if (error instanceof CeoAPIError) {
res.status(error.statusCode).json({ error: error.message });
} else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
app.listen(3000);
Submit multiple prompts concurrently and collect results.
Best for: Data analysis, parallel report generation, bulk processing
const { CeoAI } = require('@ceo-ai/sdk');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
const questions = [
'What was Q1 revenue?',
'What was Q2 revenue?',
'What was Q3 revenue?',
'What was Q4 revenue?'
];
// Submit all prompts concurrently
const submissions = await Promise.all(
questions.map(q => ceo.prompt(q))
);
console.log(`Submitted ${submissions.length} prompts`);
// Wait a bit, then collect all results
await new Promise(r => setTimeout(r, 10000));
const results = await Promise.all(
submissions.map(s => ceo.pollForResult(s.presignedUrl, {
timeout: 60000
}))
);
results.forEach((result, i) => {
console.log(`\n--- ${questions[i]} ---`);
console.log(result);
});
Keep your agent's knowledge current by training it as part of your CI/CD or deployment process.
Best for: Deployment scripts, scheduled updates, onboarding pipelines
const { CeoAI } = require('@ceo-ai/sdk');
const fs = require('fs');
const path = require('path');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
/**
* Train an agent on all supported files in a directory
*/
async function trainAgent(directory, options = {}) {
const { recursive = false, extensions = ['md', 'txt', 'json'] } = options;
const results = { succeeded: 0, failed: 0, totalCredits: 0 };
async function processDir(dir) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory() && recursive) {
if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
await processDir(fullPath);
}
continue;
}
if (!entry.isFile()) continue;
const ext = path.extname(entry.name).slice(1);
if (!extensions.includes(ext)) continue;
const stat = fs.statSync(fullPath);
if (stat.size === 0 || stat.size > 4 * 1024 * 1024) continue;
try {
const content = fs.readFileSync(fullPath, 'utf8');
const result = await ceo.addRag(content, entry.name);
console.log(`✓ ${entry.name} (${result.totalChunks} chunks, ${result.creditsDeducted} credits)`);
results.succeeded++;
results.totalCredits += result.creditsDeducted;
} catch (err) {
console.error(`✗ ${entry.name}: ${err.message}`);
results.failed++;
}
}
}
await processDir(directory);
return results;
}
// Usage
const results = await trainAgent('./docs', { recursive: true, extensions: ['md', 'txt'] });
console.log(`\nDone: ${results.succeeded} files, ${results.totalCredits} credits`);
How the SDK fits into common application architectures.
Your frontend talks to your backend. Your backend talks to CEO.ai. Your users never know about the plumbing.
┌──────────┐ ┌──────────────┐ ┌──────────┐
│ Your │────▶│ Your │────▶│ CEO.ai │
│ Frontend│ │ Backend │ │ Agent │
│ │◀────│ (SDK) │◀────│ API │
└──────────┘ └──────────────┘ └──────────┘
Submit work, store the presigned URL, and collect results asynchronously. Decouples submission from retrieval.
┌───────────┐ ┌──────────────┐ ┌──────────┐
│ Submit │────▶│ Store URL │ │ CEO.ai │
│ (SDK) │ │ in DB │ │ Agent │
└───────────┘ └──────────────┘ └──────────┘
│
(later)
│
┌───────────┐ ┌──────────────┐ ┌──────────┐
│ Collect │────▶│ Read URL │────▶│ S3 │
│ (SDK) │ │ from DB │ │ Results │
└───────────┘ └──────────────┘ └──────────┘
Different agents for different functions. Each with its own API key, its own RAG knowledge, and its own specialty.
┌──────────────────────────────────────────────┐
│ Your Application │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Support SDK │ │ Sales SDK │ │
│ │ (Agent A) │ │ (Agent B) │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ Analysis SDK│ │ Content SDK │ │
│ │ (Agent C) │ │ (Agent D) │ │
│ └─────────────┘ └─────────────┘ │
└──────────────────────────────────────────────┘
// Initialize separate clients for each agent
const support = new CeoAI({ apiKey: process.env.SUPPORT_AGENT_KEY });
const sales = new CeoAI({ apiKey: process.env.SALES_AGENT_KEY });
const analysis = new CeoAI({ apiKey: process.env.ANALYSIS_AGENT_KEY });
const content = new CeoAI({ apiKey: process.env.CONTENT_AGENT_KEY });
// Each agent has its own knowledge and specialty
const supportResponse = await support.promptAndWait(customerQuestion);
const salesResponse = await sales.promptAndWait(leadQualificationData);
Log in to the CEO.ai Dashboard
Navigate to API Keys
Click Create API Key (requires a paid subscription)
Select the agent you want this key to connect to
Copy the generated key — it's only shown once
Important
The SDK gives Node.js developers programmatic access to the same agent platform that powers CEO.ai's web app and CLI. Everything you do with the SDK — prompts, conversations, RAG training — works with the same agents and the same knowledge as the web interface and the CLI.
| If you want to… | Use… |
|---|---|
| Embed agents in your Node.js applications | SDK ← you are here |
| Talk to agents from the terminal | CLI |
| Build and manage agents visually | Web App — Agent Builder |
| Train agents on knowledge via web form | Web App — Add Memories |
| One-shot entire projects | CEO Agent |
| Automate multi-step operations | Workflows |
const { CeoAI } = require('@ceo-ai/sdk');
const ceo = new CeoAI({ apiKey: process.env.CEO_API_KEY });
const { response } = await ceo.promptAndWait('Your prompt here');
console.log(response);
Zero dependencies. Zero config files. Zero ceremony.
Just AI agents embedded in your app.
Don't have a CEO.ai account yet? Every plan includes Agent API access and full SDK support.