Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/botpress/botpress/llms.txt

Use this file to discover all available pages before exploring further.

The BotImplementation class (exported as Bot) implements the runtime behavior of a bot, including event handlers, action implementations, and lifecycle hooks.

Constructor

import { Bot } from '@botpress/sdk'
import type { Client } from '.botpress'

const bot = new Bot<typeof definition>({
  actions: { /* action implementations */ },
  plugins: { /* plugin implementations */ },
  register: async (props) => { /* registration logic */ }
})

BotImplementationProps

actions
object
required
Action handler implementations.
actions: {
  createTicket: async ({ input, client, ctx, logger }) => {
    logger.forBot().info('Creating ticket:', input)
    
    const ticket = await createTicketInExternalSystem(input)
    
    return {
      ticketId: ticket.id,
      url: ticket.url
    }
  }
}
plugins
object
required
Plugin implementation instances.
plugins: {
  analytics: analyticsPluginImpl,
  storage: storagePluginImpl
}
register
function
Registration handler called when bot is registered.
register: async ({ ctx, client, logger }) => {
  logger.forBot().info('Bot registered:', ctx.botId)
  
  // Initialize bot state
  await client.setState({
    type: 'bot',
    name: 'config',
    id: ctx.botId,
    payload: { initialized: true }
  })
}

Handler Registration

Use the on property to register event, message, and hook handlers:

Message Handlers

Handle incoming messages from channels:
import { Bot } from '@botpress/sdk'
import definition from './bot.definition'

export default new Bot({
  definition,
  actions: {},
  on: (bot) => {
    // Handle all messages
    bot.message('*', async ({ message, client, logger }) => {
      logger.forBot().info('Message received:', message.type)
    })
    
    // Handle specific message type
    bot.message('text', async ({ message, user, conversation, client }) => {
      const text = message.payload.text
      
      await client.createMessage({
        conversationId: conversation.id,
        userId: user.id,
        type: 'text',
        payload: { text: `You said: ${text}` }
      })
    })
  }
})
Handler Props:
message
Message
The incoming message with type and payload.
user
User
The user who sent the message.
conversation
Conversation
The conversation containing the message.
event
Event
The event that triggered the message.
client
BotSpecificClient
Type-safe API client.
ctx
BotContext
Bot context with configuration and IDs.
logger
BotLogger
Logger instance for the bot.
workflows
WorkflowProxy
EXPERIMENTAL - Workflow management API.

Event Handlers

Handle custom and integration events:
export default new Bot({
  definition,
  actions: {},
  on: (bot) => {
    // Handle custom event
    bot.event('issueCreated', async ({ event, client, logger }) => {
      logger.forBot().info('Issue created:', event.payload.issueId)
      
      // Create notification
      await client.createEvent({
        type: 'notificationSent',
        payload: {
          issueId: event.payload.issueId,
          sentAt: new Date().toISOString()
        }
      })
    })
    
    // Handle integration event (with alias prefix)
    bot.event('github:issueOpened', async ({ event, client }) => {
      const issue = event.payload
      
      await client.createMessage({
        conversationId: 'default-conversation',
        userId: 'bot-user',
        type: 'text',
        payload: {
          text: `New issue: ${issue.title}`
        }
      })
    })
    
    // Handle all events
    bot.event('*', async ({ event, logger }) => {
      logger.forBot().debug('Event received:', event.type)
    })
  }
})
Handler Props:
event
Event
The event with type and payload.
client
BotSpecificClient
Type-safe API client.
ctx
BotContext
Bot context.
logger
BotLogger
Logger instance.
workflows
WorkflowProxy
EXPERIMENTAL - Workflow API.

State Expiry Handlers

Handle state expiration events:
export default new Bot({
  definition,
  actions: {},
  on: (bot) => {
    bot.stateExpired('userSession', async ({ state, client, logger }) => {
      logger.forBot().info('Session expired for:', state.id)
      
      // Notify user
      await client.createMessage({
        conversationId: state.id,
        userId: state.id,
        type: 'text',
        payload: {
          text: 'Your session has expired. Please login again.'
        }
      })
    })
  }
})

Hook Handlers

Intercept and modify operations before/after execution:

Before Hooks

export default new Bot({
  definition,
  actions: {},
  on: (bot) => {
    // Intercept incoming events
    bot.beforeIncomingEvent('*', async ({ data, client, logger }) => {
      logger.forBot().info('Event incoming:', data.type)
      
      // Modify event before processing
      return {
        data: {
          ...data,
          payload: {
            ...data.payload,
            timestamp: new Date().toISOString()
          }
        }
      }
    })
    
    // Intercept incoming messages
    bot.beforeIncomingMessage('text', async ({ data, logger }) => {
      // Stop processing if message contains spam
      if (data.payload.text.includes('spam')) {
        logger.forBot().warn('Spam detected, stopping')
        return { stop: true }
      }
      
      return { data }
    })
    
    // Intercept outgoing messages
    bot.beforeOutgoingMessage('*', async ({ data }) => {
      // Add metadata to all outgoing messages
      return {
        data: {
          ...data,
          tags: {
            ...data.tags,
            sentBy: 'bot'
          }
        }
      }
    })
    
    // Intercept action calls
    bot.beforeOutgoingCallAction('*', async ({ data, logger }) => {
      logger.forBot().info('Calling action:', data.type)
      return { data }
    })
  }
})

After Hooks

export default new Bot({
  definition,
  actions: {},
  on: (bot) => {
    // Process after event received
    bot.afterIncomingEvent('*', async ({ data, logger }) => {
      logger.forBot().info('Event processed:', data.type)
      return { data }
    })
    
    // Process after message received
    bot.afterIncomingMessage('*', async ({ data, client }) => {
      // Track analytics
      await client.trackAnalytics({
        event: 'message_received',
        properties: {
          type: data.type
        }
      })
      
      return { data }
    })
    
    // Process after message sent
    bot.afterOutgoingMessage('*', async ({ data, logger }) => {
      logger.forBot().debug('Message sent:', data.message.id)
      return { data }
    })
    
    // Process after action called
    bot.afterOutgoingCallAction('*', async ({ data, logger }) => {
      logger.forBot().info('Action result:', data.output)
      return { data }
    })
  }
})

Workflow Handlers

EXPERIMENTAL - Handle workflow lifecycle events:
export default new Bot({
  definition,
  actions: {},
  on: (bot) => {
    // When workflow starts
    bot.workflowStart('onboarding', async ({ workflow, client, logger }) => {
      logger.forBot().info('Workflow started:', workflow.id)
      
      // Update workflow state
      await workflow.update({
        output: { step: 'welcome' }
      })
    })
    
    // When workflow continues
    bot.workflowContinue('onboarding', async ({ workflow, client }) => {
      // Process workflow continuation
    })
    
    // When workflow times out
    bot.workflowTimeout('onboarding', async ({ workflow, client, logger }) => {
      logger.forBot().warn('Workflow timed out:', workflow.id)
      
      // Clean up or notify
    })
  }
})

Action Implementations

Implement actions defined in the bot definition:
import { Bot } from '@botpress/sdk'
import definition from './bot.definition'

export default new Bot({
  definition,
  actions: {
    createTicket: async ({ input, client, ctx, logger, workflows }) => {
      logger.forBot().info('Creating ticket for bot:', ctx.botId)
      
      // Validate input
      if (!input.title || input.title.length < 3) {
        throw new Error('Title must be at least 3 characters')
      }
      
      // Call external API
      const ticket = await fetch('https://api.ticketing.com/tickets', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(input)
      }).then(r => r.json())
      
      // Store in bot state
      await client.setState({
        type: 'bot',
        name: 'lastTicket',
        id: ctx.botId,
        payload: { ticketId: ticket.id }
      })
      
      // Return typed output
      return {
        ticketId: ticket.id,
        url: ticket.url
      }
    },
    
    processPayment: async ({ input, client, logger }) => {
      logger.forBot().info('Processing payment:', input.amount)
      
      // Payment processing logic
      const result = await processPaymentWithProvider(input)
      
      return {
        transactionId: result.id,
        status: result.success ? 'success' : 'failed'
      }
    }
  }
})
Action Handler Props:
input
ActionInput
Type-safe action input matching the definition schema.
client
BotSpecificClient
Type-safe API client.
ctx
BotContext
Bot context with configuration.
logger
BotLogger
Logger instance.
workflows
WorkflowProxy
EXPERIMENTAL - Workflow API.

Methods

start

Start the bot HTTP server:
start(port?: number): Promise<Server>
Example:
import bot from './index'

bot.start(3000).then((server) => {
  console.log('Bot started on port 3000')
})

Properties

handler
RequestHandler
HTTP request handler for the bot.
actionHandlers
ActionHandlers
Map of action implementations.
messageHandlers
MessageHandlers
Map of message handler arrays.
eventHandlers
EventHandlers
Map of event handler arrays.
hookHandlers
HookHandlers
Map of hook handler arrays.

Complete Example

index.ts
import { Bot } from '@botpress/sdk'
import definition from './bot.definition'

export default new Bot({
  definition,
  
  // Register handler
  register: async ({ ctx, client, logger }) => {
    logger.forBot().info('Bot registered:', ctx.botId)
    
    await client.setState({
      type: 'bot',
      name: 'config',
      id: ctx.botId,
      payload: {
        version: '1.0.0',
        registeredAt: new Date().toISOString()
      }
    })
  },
  
  // Action implementations
  actions: {
    createTicket: async ({ input, client, logger }) => {
      const ticket = await createExternalTicket(input)
      
      logger.forBot().info('Ticket created:', ticket.id)
      
      return {
        ticketId: ticket.id,
        url: ticket.url
      }
    }
  },
  
  // Event and message handlers
  on: (bot) => {
    // Handle text messages
    bot.message('text', async ({ message, user, conversation, client }) => {
      const text = message.payload.text.toLowerCase()
      
      if (text.includes('help')) {
        await client.createMessage({
          conversationId: conversation.id,
          userId: user.id,
          type: 'text',
          payload: {
            text: 'How can I help you today?'
          }
          tags: {
            category: 'support'
          }
        })
      }
    })
    
    // Handle custom events
    bot.event('issueCreated', async ({ event, client, logger }) => {
      logger.forBot().info('New issue:', event.payload.issueId)
      
      // Trigger workflow or notification
    })
    
    // Before hooks for validation
    bot.beforeIncomingMessage('*', async ({ data }) => {
      // Filter spam
      if (isSpam(data.payload)) {
        return { stop: true }
      }
      return { data }
    })
    
    // After hooks for analytics
    bot.afterIncomingMessage('*', async ({ data, client }) => {
      await client.trackAnalytics({
        event: 'message_received',
        properties: { type: data.type }
      })
      return { data }
    })
  }
})

See Also