Drop AI Agents into Any Node.js App. Four Lines of Code.

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.

View on npm
quickstart.js
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..." }
Zero external dependencies Node.js 16+ MIT License TypeScript-friendly

What Makes This SDK Different

Lightweight by design. No bloat, no surprises, no dependency hell.

What you get

  • Complete access to the CEO.ai Agent API
  • Prompt, poll, conversation, and RAG training
  • Built entirely on Node.js built-in modules
  • Typed error handling with convenience getters
  • Async/await patterns that work in any Node.js app

What you don't get

  • No bloated dependency tree
  • No webpack conflicts
  • No version compatibility nightmares
  • No "please also install these 47 peer dependencies"
  • No framework lock-in

What you can build with it

Backend AI Features

Add intelligent responses, data processing, or content generation to any Express/Fastify/Koa app

AI-Powered Chatbots

Slack bots, Telegram bots, Discord bots, WhatsApp bots — all backed by your trained agents

Processing Pipelines

Batch process documents, analyze data, generate reports on a schedule

Customer-Facing AI Products

Build AI-powered SaaS features with your agents as the intelligence layer

Integration Middleware

Connect your agents to any system that runs Node.js

Internal Tools

Dashboards, admin panels, and scripts that leverage your AI agents

Installation

Terminal
$ npm install @ceo-ai/sdk

That's it. No peer dependencies. No additional installs.

Get Your API Key

  1. 1

    Log in to the CEO.ai Dashboard

  2. 2

    Navigate to API Keys

  3. 3

    Click Create API Key (requires a paid subscription)

  4. 4

    Select the agent you want this key to connect to

  5. 5

    Copy the generated key — it's only shown once

Initialize the Client

initialize.js
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 });

API Reference

METHOD

ceo.prompt(prompt, options?)

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.

prompt.js
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'  
// }

Parameters

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>


RECOMMENDED

ceo.promptAndWait(prompt, options?)

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.

promptAndWait.js
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

Parameters

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 }>


METHOD

ceo.pollForResult(presignedUrl, options?)

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.

pollForResult.js
const result = await ceo.pollForResult(presignedUrl, {  
    interval: 3000,  
    timeout: 60000,  
    onPoll: (attempt, elapsed) => {  
        console.log(`Attempt ${attempt} (${elapsed}ms elapsed)`);  
    }  
});

Parameters

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.


RAG

ceo.addRag(content, filename, options?)

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.

addRag.js
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'  
// }

Parameters

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>

Auto-detected categories by extension

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

ERROR

CeoAPIError

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.

error-handling.js
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  
    }  
}

Usage Examples

Copy-paste patterns for the most common integration scenarios.

Simple Query

The most basic usage — send a prompt, get a response.

simple.js
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);

Fire and Forget (Store URL for Later)

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

fire-and-forget.js
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);

Conversation History

Maintain context across multiple prompts. Pass the full conversation history so the agent understands the follow-up.

Best for: Chatbot interfaces, multi-turn analysis

conversation.js
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);

Disable RAG Mode

For prompts where you want the agent's base capabilities without retrieving from its trained knowledge.

no-rag.js
const { response } = await ceo.promptAndWait('What is 2 + 2?', {  
    ragMode: false  
});

Progress Tracking

Get visibility into the polling process with the onPoll callback.

Best for: CLI tools, admin dashboards, user-facing integrations

progress.js
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})`);  
    }  
});

RAG Training — Feed Knowledge to Your Agent

Train your agent on your company's documents, code, and data — programmatically.

Best for: Automated knowledge pipelines, CI/CD integration, bulk ingestion

rag-training.js
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');

Comprehensive Error Handling

Handle every error type cleanly with specific messaging for each case.

error-handling.js
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);  
    }  
}
Most Popular Integration Pattern

Express.js Integration

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

server.js
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);

Batch Processing

Submit multiple prompts concurrently and collect results.

Best for: Data analysis, parallel report generation, bulk processing

batch.js
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);    
});

Automated RAG Training Pipeline

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

train-pipeline.js
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`);

Architecture Patterns

How the SDK fits into common application architectures.

Pattern 1: AI-Powered API Backend

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     │    
└──────────┘     └──────────────┘     └──────────┘
Best for: SaaS products, web apps, mobile app backends

Pattern 2: Fire-and-Forget Processing

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  │    
└───────────┘     └──────────────┘     └──────────┘
Best for: Queue-based systems, batch processing, long-running analysis, background jobs

Pattern 3: Multi-Agent Product

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)   │           │    
│  └─────────────┘  └─────────────┘           │    
└──────────────────────────────────────────────┘
multi-agent.js
// 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);
Best for: Complex apps with multiple AI features, agencies building multi-agent products

Getting Your API Key

  1. 1

    Log in to the CEO.ai Dashboard

  2. 2

    Navigate to API Keys

  3. 3

    Click Create API Key (requires a paid subscription)

  4. 4

    Select the agent you want this key to connect to

  5. 5

    Copy the generated key — it's only shown once

Important

  • • Each API key is connected to a specific agent. To interact with different agents, create separate keys.
  • • Store keys as environment variables — never commit them to source control.
  • • If a key is compromised, revoke it immediately from the dashboard and create a new one.

Requirements & Dependencies

Node.js 16 or later

External dependencies None (zero)

Built on Node.js built-in modules

License MIT

The SDK Is One Way In. Here's the Full Picture.

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

Start Building in 4 Lines of Code.

your-app.js
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.