Skip to main content
Messages are the primary way bots communicate with users. Botpress supports multiple message types for rich interactions.

Send messages

Create messages using the client:
src/index.ts
import * as bp from '.botpress'

const bot = new bp.Bot({ actions: {} })

bot.on.message('*', async ({ message, client, ctx }) => {
  await client.createMessage({
    conversationId: message.conversationId,
    userId: ctx.botId,
    tags: {},
    type: 'text',
    payload: {
      text: 'Hello! How can I help you today?',
    },
  })
})

export default bot

Message types

Text messages

Send plain text:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'text',
  payload: {
    text: 'This is a text message',
  },
})

Type signature

const textMessageSchema = z.object({
  text: z.string().min(1),
})

Image messages

Send images:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'image',
  payload: {
    imageUrl: 'https://example.com/image.jpg',
    title: 'Optional image title',
  },
})

Type signature

const imageMessageSchema = z.object({
  imageUrl: z.string().min(1),
  title: z.string().optional(),
})

Audio messages

Send audio files:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'audio',
  payload: {
    audioUrl: 'https://example.com/audio.mp3',
    title: 'Voice message',
  },
})

Type signature

const audioMessageSchema = z.object({
  audioUrl: z.string().min(1),
  title: z.string().optional(),
})

Video messages

Send videos:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'video',
  payload: {
    videoUrl: 'https://example.com/video.mp4',
    title: 'Tutorial video',
  },
})

Type signature

const videoMessageSchema = z.object({
  videoUrl: z.string().min(1),
  title: z.string().optional(),
})

File messages

Send files:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'file',
  payload: {
    fileUrl: 'https://example.com/document.pdf',
    title: 'Report.pdf',
  },
})

Type signature

const fileMessageSchema = z.object({
  fileUrl: z.string().min(1),
  title: z.string().optional(),
})

Location messages

Send location:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'location',
  payload: {
    latitude: 45.5017,
    longitude: -73.5673,
    address: '1234 Main St, Montreal, QC',
    title: 'Our office',
  },
})

Type signature

const locationMessageSchema = z.object({
  latitude: z.number(),
  longitude: z.number(),
  address: z.string().optional(),
  title: z.string().optional(),
})

Card messages

Send interactive cards with buttons:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'card',
  payload: {
    title: 'Product Information',
    subtitle: 'Premium subscription plan',
    imageUrl: 'https://example.com/product.jpg',
    actions: [
      {
        action: 'url',
        label: 'Learn More',
        value: 'https://example.com/premium',
      },
      {
        action: 'postback',
        label: 'Subscribe Now',
        value: 'subscribe_premium',
      },
      {
        action: 'say',
        label: 'Contact Sales',
        value: 'I want to talk to sales',
      },
    ],
  },
})

Type signature

const cardSchema = z.object({
  title: z.string().min(1),
  subtitle: z.string().optional(),
  imageUrl: z.string().optional(),
  actions: z.array(
    z.object({
      action: z.enum(['postback', 'url', 'say']),
      label: z.string().min(1),
      value: z.string().min(1),
    })
  ),
})
Send multiple cards in a carousel:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'carousel',
  payload: {
    items: [
      {
        title: 'Basic Plan',
        subtitle: '$9.99/month',
        imageUrl: 'https://example.com/basic.jpg',
        actions: [
          { action: 'postback', label: 'Select', value: 'plan_basic' },
        ],
      },
      {
        title: 'Pro Plan',
        subtitle: '$19.99/month',
        imageUrl: 'https://example.com/pro.jpg',
        actions: [
          { action: 'postback', label: 'Select', value: 'plan_pro' },
        ],
      },
      {
        title: 'Enterprise Plan',
        subtitle: 'Custom pricing',
        imageUrl: 'https://example.com/enterprise.jpg',
        actions: [
          { action: 'url', label: 'Contact Us', value: 'https://example.com/contact' },
        ],
      },
    ],
  },
})

Type signature

const carouselSchema = z.object({
  items: z.array(cardSchema),
})

Choice messages (dropdown/buttons)

Send options for users to choose:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'choice',
  payload: {
    text: 'What would you like to do?',
    options: [
      { label: 'View Orders', value: 'view_orders' },
      { label: 'Track Shipment', value: 'track_shipment' },
      { label: 'Contact Support', value: 'contact_support' },
    ],
  },
})

Type signature

const choiceSchema = z.object({
  text: z.string().min(1),
  options: z.array(
    z.object({
      label: z.string().min(1),
      value: z.string().min(1),
    })
  ),
})

Bloc messages

Send multiple message items in a single bloc:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {},
  type: 'bloc',
  payload: {
    items: [
      {
        type: 'text',
        payload: { text: 'Here are your order details:' },
      },
      {
        type: 'image',
        payload: { 
          imageUrl: 'https://example.com/order.jpg',
          title: 'Order #12345',
        },
      },
      {
        type: 'text',
        payload: { text: 'Status: Shipped' },
      },
      {
        type: 'location',
        payload: {
          latitude: 45.5017,
          longitude: -73.5673,
          title: 'Current location',
        },
      },
    ],
  },
})

Type signature

const blocItemSchema = z.union([
  z.object({ type: z.literal('text'), payload: textMessageSchema }),
  z.object({ type: z.literal('image'), payload: imageMessageSchema }),
  z.object({ type: z.literal('audio'), payload: audioMessageSchema }),
  z.object({ type: z.literal('video'), payload: videoMessageSchema }),
  z.object({ type: z.literal('file'), payload: fileMessageSchema }),
  z.object({ type: z.literal('location'), payload: locationMessageSchema }),
])

const blocSchema = z.object({
  items: z.array(blocItemSchema),
})

Receive messages

Handle incoming messages with type-specific handlers:
src/index.ts
import * as bp from '.botpress'

const bot = new bp.Bot({ actions: {} })

// Handle text messages
bot.on.message('text', async ({ message, client, ctx }) => {
  const userText = message.payload.text
  console.log('User said:', userText)
  
  await client.createMessage({
    conversationId: message.conversationId,
    userId: ctx.botId,
    tags: {},
    type: 'text',
    payload: { text: `You said: ${userText}` },
  })
})

// Handle image messages
bot.on.message('image', async ({ message, client, ctx }) => {
  const imageUrl = message.payload.imageUrl
  console.log('Received image:', imageUrl)
  
  await client.createMessage({
    conversationId: message.conversationId,
    userId: ctx.botId,
    tags: {},
    type: 'text',
    payload: { text: 'Thanks for the image!' },
  })
})

// Handle all message types
bot.on.message('*', async ({ message }) => {
  console.log('Message type:', message.type)
  console.log('Message payload:', message.payload)
})

export default bot

Message tags

Add custom tags to messages:
await client.createMessage({
  conversationId: message.conversationId,
  userId: ctx.botId,
  tags: {
    category: 'notification',
    priority: 'high',
    source: 'automated',
  },
  type: 'text',
  payload: { text: 'Important notification' },
})
Define message tags in bot definition:
bot.definition.ts
export default new sdk.BotDefinition({
  message: {
    tags: {
      category: { 
        title: 'Category', 
        description: 'Message category' 
      },
      priority: { 
        title: 'Priority', 
        description: 'Message priority level' 
      },
    },
  },
})

Get messages

Retrieve message by ID:
bot.on.message('*', async ({ client, message }) => {
  const { message: msg } = await client.getMessage({
    id: message.id,
  })
  
  console.log('Message:', msg)
  console.log('Created at:', msg.createdAt)
  console.log('Type:', msg.type)
  console.log('Payload:', msg.payload)
})

List messages

List conversation messages:
bot.on.message('*', async ({ client, conversation }) => {
  const { messages } = await client.listMessages({
    conversationId: conversation.id,
    limit: 50,
  })
  
  console.log(`Found ${messages.length} messages`)
  
  for (const msg of messages) {
    console.log(`- ${msg.type}: ${JSON.stringify(msg.payload)}`) 
  }
})

Pagination

let nextToken: string | undefined
const allMessages = []

do {
  const { messages, meta } = await client.listMessages({
    conversationId: conversation.id,
    limit: 100,
    nextToken,
  })
  
  allMessages.push(...messages)
  nextToken = meta.nextToken
} while (nextToken)

console.log(`Total messages: ${allMessages.length}`)

Update messages

Update message tags:
await client.updateMessage({
  id: message.id,
  tags: {
    ...message.tags,
    processed: 'true',
    processedAt: new Date().toISOString(),
  },
})

Delete messages

Delete a message:
await client.deleteMessage({
  id: message.id,
})

Type signatures

// Message
type Message = {
  id: string
  conversationId: string
  userId: string
  type: string
  payload: any
  tags: Record<string, string>
  createdAt: string
  updatedAt: string
}

// Create message request
type CreateMessageRequest = {
  conversationId: string
  userId: string
  type: string
  payload: any
  tags: Record<string, string>
}

// Available message types
type MessageType = 
  | 'text'
  | 'image' 
  | 'audio'
  | 'video'
  | 'file'
  | 'location'
  | 'card'
  | 'carousel'
  | 'choice'
  | 'dropdown'
  | 'bloc'

Next steps

Conversations

Manage conversations and users

Bot handlers

Implement message handlers

Build docs developers (and LLMs) love