Twilio
SMS sending and receiving
git clone https://github.com/bijectionhq/twilio.git
cd twilio
git checkout 0308857a45349e59d3be429350720779acbabc88Bijection repository access is required. Request access.
Description
SMS sending and receiving
Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.
Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.
Getting started
- Get the source at the revision above and read its package documentation.
- Check the required Bijection SDK version, dependencies, and external service credentials.
- Follow the package setup instructions and the guide to using components.
- Exercise the component in your deployment according to your project’s verification rules.
Open source
Maintained source: bijectionhq/twilio. Based on convex/twilio. License: Apache-2.0. Consult the repository for license terms, notices, and contributor attribution.
From the upstream publisher
Convex component for sending/receiving SMS messages with Twilio.
Upstream overview
From the upstream package documentation.
This Twilio component integrates SMS messaging capabilities into your Convex app. It handles both sending outgoing messages through Twilio's API and receiving incoming messages via webhook handlers. The component automatically stores message status updates and provides query functions to retrieve message history, enabling you to build SMS-driven features without managing webhook infrastructure or message persistence.
Use cases
From the upstream package documentation.
- Build notification systems that send SMS alerts for order updates, appointment reminders, or security events
- Create two-way SMS customer support where users can text your business number and agents can respond
- Implement SMS-based authentication flows with verification codes sent through Twilio
- Build SMS marketing campaigns that track delivery status and handle opt-out responses
- Create SMS chatbots that process incoming messages and respond based on business logic
How it works
From the upstream package documentation.
The component requires Twilio API credentials and registers HTTP webhook routes (/twilio/message-status and /twilio/incoming-message) in your Convex app. You instantiate a Twilio client in your functions and call sendMessage() from actions to send SMS messages.
For incoming messages, you associate your Twilio phone number with the webhook URL either through the Twilio console or by calling registerIncomingSmsHandler(). The component automatically stores all messages in a database table and provides query methods like list(), getMessageBySid(), and getMessagesByCounterparty().
You can execute custom logic on incoming messages by setting an incomingMessageCallback that runs in the same transaction as message storage. The component tracks message delivery status updates from Twilio, so you can monitor whether SMS messages were successfully delivered.
Upstream package FAQ
How do I configure Twilio credentials for the Convex Twilio component?
Store your Twilio Account SID and Auth Token as environment variables in your Convex deployment. The Convex Twilio component automatically reads these credentials and handles authentication with the Twilio API for all SMS operations.
Can I query SMS message status without making additional API calls?
Yes, the Convex Twilio component stores message status in your Convex database and provides query functions to retrieve delivery status. This eliminates the need for additional Twilio API calls when checking message delivery status.
Does the component handle Twilio webhook verification?
The Convex Twilio component includes built-in webhook signature verification to ensure incoming SMS messages are actually from Twilio. This security feature validates webhook authenticity before processing incoming message data.
What happens if SMS sending fails with the Twilio component?
The Convex Twilio component provides structured error handling for failed SMS messages, including rate limiting, invalid numbers, and network errors. Failed messages are logged with error details in your Convex database for debugging and retry logic.
Use with agents and CLI
Give your coding agent the component’s source identity and setup guidance.
Help me integrate Twilio with Bijection.
Read: https://bijection.com/components/twilio/SKILL.md
Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.Upstream README.md
View repository ↗Documentation from convex/twilio, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.
Send and receive SMS messages in your Convex app using Twilio.
import { Twilio } from "@convex-dev/twilio";
import { components } from "./_generated/api";
export const twilio = new Twilio(components.twilio, {
defaultFrom: process.env.TWILIO_PHONE_NUMBER!,
});
export const sendSms = internalAction({
handler: async (ctx, args) => {
return await twilio.sendMessage(ctx, {
to: "+14151234567",
body: "Hello, world!",
});
},
});
Prerequisites
Twilio Phone Number
Create a Twilio account and, if you haven't already, create a Twilio Phone Number.
Note the Phone Number SID of the phone number you'll be using, you'll need it in a moment.
Convex App
You'll need a Convex App to use the component. Follow any of the Convex quickstarts to set one up.
Installation
Install the component package:
npm install @convex-dev/twilio
Create a convex.config.ts file in your app's convex/ folder and install the
component by calling use:
// convex/convex.config.ts
import { defineApp } from "convex/server";
import twilio from "@convex-dev/twilio/convex.config.js";
const app = defineApp();
app.use(twilio);
export default app;
Set your API credentials:
npx convex env set TWILIO_ACCOUNT_SID=ACxxxxx
npx convex env set TWILIO_AUTH_TOKEN=xxxxx
Instantiate a Twilio Component client in a file in your app's convex/ folder:
// convex/example.ts
import { Twilio } from "@convex-dev/twilio";
import { components } from "./_generated/api";
export const twilio = new Twilio(components.twilio, {
// optionally pass in the default "from" phone number you'll be using
// this must be a phone number you've created with Twilio
defaultFrom: process.env.TWILIO_PHONE_NUMBER!,
});
Register Twilio webhook handlers by creating an http.ts file in your convex/
folder and use the client you've exported above:
// http.ts
import { twilio } from "./example";
import { httpRouter } from "convex/server";
const http = httpRouter();
// this call registers the routes necessary for the component
twilio.registerRoutes(http);
export default http;
Sending Messages
To send a message use the Convex action sendMessage:
// convex/messages.ts
import { v } from "convex/values";
import { internalAction } from "./_generated/server";
export const sendSms = internalAction({
handler: async (ctx, args) => {
const status = await twilio.sendMessage(ctx, {
to: "+14158675309",
body: "Hey Jenny",
});
},
});
By querying the message (see below) you can check for the status (Twilio Statuses). The component subscribes to status updates and writes the most up-to-date status into the database.
Receiving Messages
To receive messages, you will associate a webhook handler provided by the component with the Twilio phone number you'd like to use.
twilio.registerRoutes registers two webhook HTTP handlers in your your Convex
app's deployment:
YOUR_CONVEX_SITE_URL/twilio/message-status- capture and store delivery status of messages you send.YOUR_CONVEX_SITE_URL/twilio/incoming-message- capture and store messages sent to your Twilio phone number.
Note: You may pass a custom httpPrefix to Twilio if you want to route Twilio
endpoints somewhere other than YOUR_CONVEX_SITE_URL/twilio/*.
For instance, to route to YOUR_CONVEX_SITE_URL/custom-twilio/message-status,
set:
export const twilio = new Twilio(components.twilio, {
httpPrefix: "/custom-twilio",
});
You can associate it with your Twilio phone number in two ways:
-
Using the Twilio console in the "Configure" tab of the phone number, under "Messaging Configuration" -> "A messsage comes in" -> "URL".
-
By calling
registerIncomingSmsHandlerexposed by the component client, passing it the phone number's SID:
export const registerIncomingSmsHandler = internalAction({
args: {},
handler: async (ctx) => {
return await twilio.registerIncomingSmsHandler(ctx, {
sid: "YOUR_TWILIO_PHONE_NUMBER_SID",
});
},
});
Once it is configured, incoming messages will be captured by the component and
logged in the messages table.
You can execute your own logic upon receiving an incoming message, by providing a callback when instantiating the Twilio Component client:
// convex/example.ts
import { Twilio, messageValidator } from "@convex-dev/twilio";
const twilio = new Twilio(components.twilio);
twilio.incomingMessageCallback = internal.example.handleIncomingMessage;
export const handleIncomingMessage = internalMutation({
args: {
message: messageValidator,
},
handler: async (ctx, message) => {
// Use ctx here to update the database or schedule other actions.
// This is in the same transaction as the component's message insertion.
console.log("Incoming message", message);
},
});
If the handleIncomingMessage callback throws an error, the message will not be
saved and the webhook will throw an error. Twilio
does not retry webhook requests,
but you can replay them manually from the Twilio "Error logs" console.
Querying Messages
To list all the mssages, use the list method in your Convex function.
To list all the incoming or outgoing messages, use listIncoming and
listOutgoing methods:
// convex/messages.ts
// ...
export const list = query({
args: {},
handler: async (ctx) => {
const allMessages = await twilio.list(ctx);
const receivedMessages = await twilio.listIncoming(ctx);
const sentMessages = await twilio.listOutgoing(ctx);
return { allMessages, receivedMessages, sentMessages };
},
});
To get a single message by its sid, use getMessageBySid:
export const getMessageBySid = query({
args: {
sid: v.string(),
},
handler: async (ctx, args) => {
return await twilio.getMessageBySid(ctx, args);
},
});
Get messages by the "to" phone number:
export const getMessagesTo = query({
args: {
to: v.string(),
},
handler: async (ctx, args) => {
return await twilio.getMessagesTo(ctx, args);
},
});
Get messages by the "from" phone number:
export const getMessagesFrom = query({
args: {
from: v.string(),
},
handler: async (ctx, args) => {
return await twilio.getMessagesFrom(ctx, args);
},
});
You can also get all messages to and from a particular number:
export const getMessagesByCounterparty = query({
args: {
from: v.string(),
},
handler: async (ctx, args) => {
return await twilio.getMessagesByCounterparty(ctx, args);
},
});