Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions integrations/twilio/hub.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
- You can now use the action card GetOrCreateUser to get or create a user.
- The markdown message type is replaced by markdown support in all texts.

## New in version 1.3.0

- Typing/Read indicators are now sent for WhatsApp conversations.

## Description

The Twilio integration enables seamless communication between your AI-powered chatbot and Twilio, a powerful cloud communications platform. Connect your chatbot to Twilio and leverage a wide range of communication channels, including SMS, voice calls, and messaging apps. With this integration, you can automate interactions, send personalized notifications, handle inquiries, and provide customer support directly through Twilio. Utilize Twilio's extensive features such as SMS delivery, call routing, message templates, and more to create robust and efficient conversational experiences. Enhance your communication strategy and reach customers effectively with the Twilio Integration for Botpress.
4 changes: 3 additions & 1 deletion integrations/twilio/integration.definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { IntegrationDefinition } from '@botpress/sdk'
import { sentry as sentryHelpers } from '@botpress/sdk-addons'
import proactiveConversation from 'bp_modules/proactive-conversation'
import proactiveUser from 'bp_modules/proactive-user'
import typingIndicator from 'bp_modules/typing-indicator'
import { channels, configuration, entities, user } from './definitions'

export const INTEGRATION_NAME = 'twilio'
export const INTEGRATION_VERSION = '1.2.0'
export const INTEGRATION_VERSION = '1.3.0'

export default new IntegrationDefinition({
name: INTEGRATION_NAME,
Expand All @@ -27,6 +28,7 @@ export default new IntegrationDefinition({
},
},
})
.extend(typingIndicator, () => ({ entities: {} }))
.extend(proactiveConversation, ({ entities }) => ({
entities: {
conversation: entities.conversation,
Expand Down
6 changes: 4 additions & 2 deletions integrations/twilio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@
"@botpress/sdk-addons": "workspace:*",
"axios": "^1.6.0",
"query-string": "^6.14.1",
"twilio": "^3.84.0"
"twilio": "^5.4.0"
},
"devDependencies": {
"@botpress/cli": "workspace:*",
"@botpress/common": "workspace:*",
"@botpress/sdk": "workspace:*",
"@botpresshub/proactive-conversation": "workspace:*",
"@botpresshub/proactive-user": "workspace:*",
"@botpresshub/typing-indicator": "workspace:*",
"@sentry/cli": "^2.39.1"
},
"bpDependencies": {
"proactive-conversation": "../../interfaces/proactive-conversation",
"proactive-user": "../../interfaces/proactive-user"
"proactive-user": "../../interfaces/proactive-user",
"typing-indicator": "../../interfaces/typing-indicator"
}
}
3 changes: 3 additions & 0 deletions integrations/twilio/src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import * as bp from '../../.botpress'
import { getOrCreateUser } from './get-or-create-user'
import { startConversation } from './start-conversation'
import { startTypingIndicator, stopTypingIndicator } from './typing-indicator'

export const actions = {
getOrCreateUser,
startConversation,
startTypingIndicator,
stopTypingIndicator,
} satisfies bp.IntegrationProps['actions']
65 changes: 65 additions & 0 deletions integrations/twilio/src/actions/typing-indicator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as bp from '../../.botpress'
import { getTwilioClient } from '../twilio'
import { getPhoneNumbers, getTwilioChannelType } from '../utils'

async function sendTypingIndicator({
client,
ctx,
conversationId,
messageId,
}: {
client: bp.Client
ctx: bp.Context
conversationId: string
messageId: string
}): Promise<void> {
const { conversation } = await client.getConversation({ id: conversationId })
const { to } = getPhoneNumbers(conversation)
const channelType = getTwilioChannelType(to)

// Typing indicators only supported for WhatsApp
if (channelType !== 'whatsapp') {
return
}

const { message } = await client.getMessage({ id: messageId })
const twilioMessageSid = message.tags?.id

if (!twilioMessageSid) {
return
}

const twilioClient = getTwilioClient(ctx)

// The Twilio SDK doesn't expose the v2 Indicators API natively yet (Its in beta),
// so we use client.request() to call the REST endpoint directly
await twilioClient.request({
method: 'post',
uri: 'https://messaging.twilio.com/v2/Indicators/Typing.json',
data: {
messageId: twilioMessageSid,
channel: 'whatsapp',
},
})
}

export const startTypingIndicator: bp.IntegrationProps['actions']['startTypingIndicator'] = async ({
client,
ctx,
input,
logger,
}) => {
try {
const { conversationId, messageId } = input
await sendTypingIndicator({ client, ctx, conversationId, messageId })
} catch (error) {
const thrown = error instanceof Error ? error : new Error(String(error))
logger.forBot().warn(`Failed to send typing indicator: ${thrown.message ?? '[Unknown error]'}`)
}
return {}
}

export const stopTypingIndicator: bp.IntegrationProps['actions']['stopTypingIndicator'] = async () => {
// Twilio's typing indicator automatically stops after 25 seconds or when a message is sent.
return {}
}
2 changes: 1 addition & 1 deletion integrations/twilio/src/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async function sendMessage({ ctx, conversation, ack, mediaUrl, text, logger }: S
)
}
}
const { sid } = await twilioClient.messages.create({ to, from, mediaUrl, body })
const { sid } = await twilioClient.messages.create({ to, from, mediaUrl: mediaUrl ? [mediaUrl] : undefined, body })
await ack({ tags: { id: sid } })
}

Expand Down
Loading
Loading