Skip to main content
BuilderBot includes a built-in HTTP server that lets you create custom API endpoints. Use these to send messages, trigger flows, manage blacklists, and control your bot externally.

HTTP Server Setup

The HTTP server starts automatically when you initialize the bot:
import { createBot, createProvider, createFlow } from '@builderbot/bot'
import { BaileysProvider } from '@builderbot/provider-baileys'

const PORT = process.env.PORT ?? 3008

const main = async () => {
    const adapterFlow = createFlow([welcomeFlow])
    const adapterProvider = createProvider(BaileysProvider)
    const adapterDB = new MemoryDB()

    const { handleCtx, httpServer } = await createBot({
        flow: adapterFlow,
        provider: adapterProvider,
        database: adapterDB,
    })

    // Server starts on specified port
    httpServer(+PORT)
    console.log(`Server running on http://localhost:${PORT}`)
}

main()

Creating Endpoints

Use handleCtx() to create endpoints that have access to your bot instance:

Basic POST Endpoint

adapterProvider.server.post(
    '/v1/messages',
    handleCtx(async (bot, req, res) => {
        const { number, message } = req.body
        
        await bot.sendMessage(number, message, {})
        
        return res.end('sent')
    })
)

Basic GET Endpoint

adapterProvider.server.get(
    '/v1/status',
    handleCtx(async (bot, req, res) => {
        res.writeHead(200, { 'Content-Type': 'application/json' })
        return res.end(JSON.stringify({ 
            status: 'online',
            timestamp: Date.now()
        }))
    })
)

Sending Messages

Create an endpoint to send text messages:
1

Create message endpoint

adapterProvider.server.post(
    '/v1/messages',
    handleCtx(async (bot, req, res) => {
        const { number, message, urlMedia } = req.body
        
        await bot.sendMessage(number, message, { 
            media: urlMedia ?? null 
        })
        
        return res.end('sent')
    })
)
2

Test with cURL

curl -X POST http://localhost:3008/v1/messages \
  -H "Content-Type: application/json" \
  -d '{
    "number": "1234567890",
    "message": "Hello from API!"
  }'
3

Send with media

curl -X POST http://localhost:3008/v1/messages \
  -H "Content-Type: application/json" \
  -d '{
    "number": "1234567890",
    "message": "Check this image",
    "urlMedia": "https://example.com/image.jpg"
  }'

Triggering Flows

Trigger conversation flows programmatically:

Dispatch Custom Events

// Create event-based flow
const registerFlow = addKeyword(utils.setEvent('REGISTER_FLOW'))
    .addAnswer('What is your name?', { capture: true }, async (ctx, { state }) => {
        await state.update({ name: ctx.body })
    })
    .addAnswer('What is your age?', { capture: true }, async (ctx, { state }) => {
        await state.update({ age: ctx.body })
    })

// Create endpoint to trigger flow
adapterProvider.server.post(
    '/v1/register',
    handleCtx(async (bot, req, res) => {
        const { number, name } = req.body
        
        // Trigger the REGISTER_FLOW event
        await bot.dispatch('REGISTER_FLOW', { 
            from: number, 
            name 
        })
        
        return res.end('flow triggered')
    })
)

Test Flow Trigger

curl -X POST http://localhost:3008/v1/register \
  -H "Content-Type: application/json" \
  -d '{
    "number": "1234567890",
    "name": "John"
  }'

Blacklist Management

Create endpoints to manage the blacklist:

Add/Remove from Blacklist

adapterProvider.server.post(
    '/v1/blacklist',
    handleCtx(async (bot, req, res) => {
        const { number, intent } = req.body
        
        if (intent === 'remove') {
            bot.blacklist.remove(number)
        } else if (intent === 'add') {
            bot.blacklist.add(number)
        }
        
        res.writeHead(200, { 'Content-Type': 'application/json' })
        return res.end(JSON.stringify({ 
            status: 'ok', 
            number, 
            intent 
        }))
    })
)

Get Blacklist

adapterProvider.server.get(
    '/v1/blacklist/list',
    handleCtx(async (bot, req, res) => {
        const blacklist = bot.blacklist.getList()
        
        res.writeHead(200, { 'Content-Type': 'application/json' })
        return res.end(JSON.stringify({ 
            status: 'ok', 
            blacklist 
        }))
    })
)

Test Blacklist API

# Add to blacklist
curl -X POST http://localhost:3008/v1/blacklist \
  -H "Content-Type: application/json" \
  -d '{
    "number": "1234567890",
    "intent": "add"
  }'

# Get blacklist
curl http://localhost:3008/v1/blacklist/list

# Remove from blacklist
curl -X POST http://localhost:3008/v1/blacklist \
  -H "Content-Type: application/json" \
  -d '{
    "number": "1234567890",
    "intent": "remove"
  }'

State Management via API

Access and modify state through HTTP endpoints:

Get User State

adapterProvider.server.get(
    '/v1/user/:number/state',
    handleCtx(async (bot, req, res) => {
        const { number } = req.params
        const state = bot.state(number).getMyState()
        
        res.writeHead(200, { 'Content-Type': 'application/json' })
        return res.end(JSON.stringify({ state }))
    })
)

Update User State

adapterProvider.server.post(
    '/v1/user/:number/state',
    handleCtx(async (bot, req, res) => {
        const { number } = req.params
        const data = req.body
        
        await bot.state(number).update(data)
        
        res.writeHead(200, { 'Content-Type': 'application/json' })
        return res.end(JSON.stringify({ status: 'ok' }))
    })
)

Clear User State

adapterProvider.server.delete(
    '/v1/user/:number/state',
    handleCtx(async (bot, req, res) => {
        const { number } = req.params
        
        bot.state(number).clear()
        
        res.writeHead(200, { 'Content-Type': 'application/json' })
        return res.end(JSON.stringify({ status: 'cleared' }))
    })
)

Request Parameters

Access different types of request data:
adapterProvider.server.get(
    '/v1/user/:id/messages/:messageId',
    handleCtx(async (bot, req, res) => {
        const { id, messageId } = req.params
        console.log('User ID:', id)
        console.log('Message ID:', messageId)
        
        // Your logic here
        res.end('ok')
    })
)
adapterProvider.server.get(
    '/v1/search',
    handleCtx(async (bot, req, res) => {
        const { query, limit, offset } = req.query
        console.log('Search query:', query)
        console.log('Limit:', limit)
        console.log('Offset:', offset)
        
        // Your logic here
        res.end('ok')
    })
)
// Call: GET /v1/search?query=test&limit=10&offset=0
adapterProvider.server.post(
    '/v1/data',
    handleCtx(async (bot, req, res) => {
        const { name, email, phone } = req.body
        console.log('Received:', { name, email, phone })
        
        // Your logic here
        res.end('ok')
    })
)

Response Formats

JSON Response

adapterProvider.server.get(
    '/v1/data',
    handleCtx(async (bot, req, res) => {
        const data = {
            users: 100,
            messages: 5000,
            uptime: process.uptime()
        }
        
        res.writeHead(200, { 'Content-Type': 'application/json' })
        return res.end(JSON.stringify(data))
    })
)

Text Response

adapterProvider.server.get(
    '/v1/health',
    handleCtx(async (bot, req, res) => {
        res.writeHead(200, { 'Content-Type': 'text/plain' })
        return res.end('OK')
    })
)

Error Response

adapterProvider.server.post(
    '/v1/send',
    handleCtx(async (bot, req, res) => {
        try {
            const { number, message } = req.body
            
            if (!number || !message) {
                res.writeHead(400, { 'Content-Type': 'application/json' })
                return res.end(JSON.stringify({ 
                    error: 'Missing required fields' 
                }))
            }
            
            await bot.sendMessage(number, message, {})
            res.writeHead(200, { 'Content-Type': 'application/json' })
            return res.end(JSON.stringify({ status: 'sent' }))
            
        } catch (error) {
            res.writeHead(500, { 'Content-Type': 'application/json' })
            return res.end(JSON.stringify({ 
                error: error.message 
            }))
        }
    })
)

Complete API Example

import { createBot, createProvider, createFlow, addKeyword, utils } from '@builderbot/bot'
import { MemoryDB } from '@builderbot/bot'
import { BaileysProvider } from '@builderbot/provider-baileys'

const PORT = process.env.PORT ?? 3008

const registerFlow = addKeyword(utils.setEvent('REGISTER_FLOW'))
    .addAnswer('What is your name?', { capture: true }, async (ctx, { state }) => {
        await state.update({ name: ctx.body })
    })

const main = async () => {
    const adapterFlow = createFlow([registerFlow])
    const adapterProvider = createProvider(BaileysProvider)
    const adapterDB = new MemoryDB()

    const { handleCtx, httpServer } = await createBot({
        flow: adapterFlow,
        provider: adapterProvider,
        database: adapterDB,
    })

    // Send message endpoint
    adapterProvider.server.post(
        '/v1/messages',
        handleCtx(async (bot, req, res) => {
            const { number, message, urlMedia } = req.body
            await bot.sendMessage(number, message, { media: urlMedia ?? null })
            return res.end('sent')
        })
    )

    // Trigger flow endpoint
    adapterProvider.server.post(
        '/v1/register',
        handleCtx(async (bot, req, res) => {
            const { number, name } = req.body
            await bot.dispatch('REGISTER_FLOW', { from: number, name })
            return res.end('triggered')
        })
    )

    // Blacklist management
    adapterProvider.server.post(
        '/v1/blacklist',
        handleCtx(async (bot, req, res) => {
            const { number, intent } = req.body
            if (intent === 'remove') bot.blacklist.remove(number)
            if (intent === 'add') bot.blacklist.add(number)
            
            res.writeHead(200, { 'Content-Type': 'application/json' })
            return res.end(JSON.stringify({ status: 'ok', number, intent }))
        })
    )

    // Get blacklist
    adapterProvider.server.get(
        '/v1/blacklist/list',
        handleCtx(async (bot, req, res) => {
            const blacklist = bot.blacklist.getList()
            res.writeHead(200, { 'Content-Type': 'application/json' })
            return res.end(JSON.stringify({ status: 'ok', blacklist }))
        })
    )

    // Health check
    adapterProvider.server.get(
        '/v1/health',
        handleCtx(async (bot, req, res) => {
            res.writeHead(200, { 'Content-Type': 'application/json' })
            return res.end(JSON.stringify({ 
                status: 'online',
                uptime: process.uptime()
            }))
        })
    )

    httpServer(+PORT)
    console.log(`🚀 Server running on http://localhost:${PORT}`)
}

main()

Bot Instance Methods

These methods are available on the bot object in handleCtx:
MethodDescription
bot.sendMessage(number, message, options)Send a message to a number
bot.dispatch(event, context)Trigger a custom event flow
bot.blacklist.add(number)Add number to blacklist
bot.blacklist.remove(number)Remove number from blacklist
bot.blacklist.getList()Get all blacklisted numbers
bot.state(number)Access user state
bot.globalState()Access global state
bot.providerAccess provider instance

Best Practices

Always validate request data:
adapterProvider.server.post('/v1/send',
    handleCtx(async (bot, req, res) => {
        const { number, message } = req.body
        
        if (!number || !message) {
            res.writeHead(400, { 'Content-Type': 'application/json' })
            return res.end(JSON.stringify({ error: 'Missing fields' }))
        }
        
        // Process request...
    })
)
Wrap logic in try-catch blocks:
adapterProvider.server.post('/v1/action',
    handleCtx(async (bot, req, res) => {
        try {
            // Your logic
            res.end('ok')
        } catch (error) {
            console.error(error)
            res.writeHead(500, { 'Content-Type': 'application/json' })
            res.end(JSON.stringify({ error: 'Internal error' }))
        }
    })
)
  • GET: Retrieve data
  • POST: Create/trigger actions
  • PUT/PATCH: Update data
  • DELETE: Remove data
Add authentication:
const authenticate = (req) => {
    const token = req.headers['authorization']
    return token === `Bearer ${process.env.API_TOKEN}`
}

adapterProvider.server.post('/v1/send',
    handleCtx(async (bot, req, res) => {
        if (!authenticate(req)) {
            res.writeHead(401, { 'Content-Type': 'application/json' })
            return res.end(JSON.stringify({ error: 'Unauthorized' }))
        }
        // Your logic...
    })
)

Next Steps

Build docs developers (and LLMs) love