Skip to content

Send actions and handle intents

Actions let your agent send a message with tappable buttons. When the user picks one, the agent gets an intent event with the selected button's ID. This works well for confirmations, payment flows, menu navigation, and polls.

Send actions

Node
await ctx.conversation.sendActions({
  id: `actions-${Date.now()}`,
  description: 'Would you like to proceed?',
  actions: [
    { id: 'action-yes', label: 'Yes', style: 'primary' },
    { id: 'action-no', label: 'No', style: 'secondary' },
  ],
});

Each action button has the following fields:

  • id: Returned as actionId in the intent when tapped
  • label: The button text
  • style (optional): "primary", "secondary", or "danger"
  • imageUrl (optional): An image to show alongside the button
  • expiresAt (optional): ISO 8601 timestamp after which the button expires

Set a top-level expiresAt to expire the entire prompt.

Payment example

Node
await ctx.conversation.sendActions({
  id: 'payment_alice_123',
  description: 'Choose amount to send',
  actions: [
    { id: 'send_10', label: 'Send $10', style: 'primary' },
    { id: 'send_20', label: 'Send $20', style: 'primary' },
  ],
});

Receive an intent

When a user taps a button, the SDK fires an "intent" event. Match on actionId to know which button was pressed.

Node
agent.on('intent', async (ctx) => {
  const { actionId } = ctx.message.content;
 
  if (actionId === 'send_10') {
    await ctx.conversation.sendText('Sending $10...');
  } else if (actionId === 'send_20') {
    await ctx.conversation.sendText('Sending $20...');
  }
});

The intent payload has three fields:

  • id: The ID of the original action prompt
  • actionId: The ID of the button that was tapped
  • metadata (optional): Key-value context sent by the client