Every calendar has a collision in it somewhere. Two meetings at the same time, a dentist appointment that ran long, a train with no signal for the first ten minutes of a standup.
The usual fix is an apology message and a request for notes afterward. I wanted something better: text a link, and a bot goes in my place.
I built a Node.js Telnyx code example that does exactly that. You send a meeting link to a Telnyx number. A bot joins the meeting, posts a note in the chat explaining who it is, takes notes, and texts you a TL;DR when the meeting ends.
The code example:
https://github.com/team-telnyx/telnyx-code-examples/tree/main/join-meeting-by-sms-nodejs
The video walkthrough:
The Use Case
The interaction is a single text:
I can't join this meeting: https://meet.google.com/abc-defg-hij.
Join as my bot, and send me a TL;DR when it ends.
~~~
A moment later a reply arrives:
~~~plaintext
On it. Your bot is joining now. I will text you when it is in
and send a TL;DR after the meeting.
~~~
In the meeting, a new participant appears with the bot's name and posts a chat message telling everyone it is taking notes on someone's behalf. When the meeting ends, a second text arrives with the summary.
The phone is the interface because it is the one thing you have when you cannot get to a laptop.
## What The Example Uses
The example runs as a small Express server and uses two Telnyx products with one API key:
- Telnyx Messaging to receive the inbound text and send the replies
- Telnyx Meeting Bot to join the call, capture the transcript, and generate a summary
- Telnyx webhooks with Ed25519 signatures to authenticate inbound messages
There is no separate transcription service and no separate summarization step in the code. The session is created with `summarize_on_end: true`, and Telnyx produces a summary artifact when the meeting is over.
## Keeping It Safe
A bot you can summon by text is also a bot someone else might try to summon, so the example has two guards.
First, the webhook verifies the Telnyx signature over the raw request body. A request that does not carry a valid signature gets a `401` and nothing else happens.
Second, the handler only acts on texts from one configured number, the owner's mobile. Messages from anyone else are ignored.
~~~js
if (from !== OWNER_PHONE_NUMBER) {
return;
}
~~~
That is enough for a personal tool. It is not an access-control system, and a team version would need real per-user rules.
## Sending The Bot In
The core of the example is one API call:
~~~js
await client.meetingSessions.create({
meeting_url: meetingUrl,
bot_name: BOT_NAME,
chat_on_enter: CHAT_ON_ENTER,
summarize_on_end: true,
idempotency_key: `join-meeting-by-sms:${messageId}`,
});
~~~
The `idempotency_key` solves a quiet problem. Telnyx retries webhooks that do not get a quick success response, and a retry must not put a second bot in the meeting. Because the key comes from the inbound message ID, a replayed message resolves to the session that already exists.
The `chat_on_enter` message matters for a human reason. A silent unknown participant is unsettling. A bot that introduces itself is a much better guest.
## Telling You What Is Happening
Joining a meeting is not instant. A host may need to admit the bot from a waiting room, and a host may decline. The server polls the session every few seconds and texts you on each change:
~~~json
waiting_for_admission -> a host needs to admit your bot
active -> your bot is in and taking notes
admission_denied -> the host did not admit your bot
failed -> your bot could not join
~~~
Each status is texted once, so you are not flooded while waiting.
## Getting The TL;DR
When the session ends, the server asks for the session's artifacts and picks out the one with type `summary`. Summary generation is asynchronous, so the server waits for it to complete, up to ninety seconds, then texts it to you.
If the summary is not available, you get a clear fallback message. A silent failure would be worse than an honest one.
## Optional Extras
Two environment variables make the bot feel more like a participant:
- `ASSISTANT_ID` attaches a Telnyx AI Assistant so the bot can speak and answer questions in the meeting
- `CAMERA_IMAGE_URL` sets a static image as the bot's camera tile
## Running The Example
~~~bash
git clone https://github.com/team-telnyx/telnyx-code-examples.git
cd telnyx-code-examples/join-meeting-by-sms-nodejs
cp .env.example .env
npm install
npm start
~~~
Add your API key, public key, Telnyx number, and your own mobile number to `.env`. Expose the server with a tunnel, point your Messaging Profile's inbound webhook at `/webhooks/sms`, and text your number a link.
This puts a real bot in a real meeting and sends real SMS, so try it on a meeting you control first.
## What I Would Change For Production
This is a pattern, not a product. Before using it for real I would:
- Store watched session IDs in a database so a restart does not drop the status texts
- Always disclose the bot in chat, because people deserve to know when a meeting is being summarized
- Register the sending number for US SMS with 10DLC or toll-free verification
- Replace the single owner number with per-user rules
- Plan for meeting platforms where chat is not supported
## Frequently Asked Questions
### Which meeting platforms work?
The example recognizes Google Meet, Zoom, Microsoft Teams, and Webex links.
### Can the bot talk?
Yes, if you attach a Telnyx AI Assistant with `ASSISTANT_ID`.
### What if the host never admits the bot?
You get a text saying the bot is at the waiting room, and another if the host denies admission.
### Can someone else text the bot into a meeting?
No. Only the configured owner number is accepted, and webhooks without a valid Telnyx signature are rejected.
## First comment
Demo video: https://youtu.be/cQMwlgGuU5E
Code: https://github.com/team-telnyx/telnyx-code-examples/tree/main/join-meeting-by-sms-nodejs
Top comments (0)