Skip to main content

How to build a WhatsApp bot for to-do lists using Bird’s Programmable Conversations API

Bird’s Programmable Conversations API unifies WhatsApp, Messenger, and SMS into one seamless communication solution for businesses.

How to build a WhatsApp bot for to-do lists using Bird’s Programmable Conversations API

Key Takeaways

  • Bird’s Programmable Conversations API unifies WhatsApp, Messenger, and SMS into a single communication layer, simplifying multi-channel bot development.
  • You can quickly prototype a WhatsApp to-do list bot using webhooks and simple POST requests.
  • Tools like ngrok let you expose your local server for webhook testing without complex hosting setup.
  • The API handles conversations across multiple channels, allowing one logic base for WhatsApp, WeChat, and other apps.
  • Use the archiveConversation endpoint to close conversations or "topics," ideal for support or workflow tracking.
  • The bot logic can manage concurrent conversations safely in memory with a simple data structure.
  • The same webhook handler works across channels—Bird automatically routes replies based on the originating conversation ID.

Q&A Highlights

  • How hard is it to build a WhatsApp bot using Bird’s API?It’s surprisingly easy. With a webhook and a few API calls, you can build a functional bot that reads and replies to messages within minutes.
  • Do I need special setup to receive messages?Yes — the bot must be reachable from the internet. Tools like ngrok help create a secure tunnel from your local machine.
  • Can I use the same codebase for different messaging apps?Absolutely. The Conversations API abstracts channels, so your bot can run on WhatsApp, WeChat, or Messenger using identical logic.
  • How do I close or reset a chat thread?Send a PATCH request to the conversation’s endpoint with the proper status to archive it. Any new message automatically opens a new conversation.
  • Where can I find example code?A: The full working demo — Wabot on GitHub — shows the implementation of message handling, concurrency, and archiving.

Bird recently launched Programmable Conversations. It lets companies blend communications platforms like WhatsApp, Messenger and SMS into their systems — using a single API.

I wanted to give it a whirl, so I built a WhatsApp bot to-do list, because who doesn’t need an automated to-do list to help organize their day? It may sound complicated, but it was actually easy, and I’d like to tell you all about it.

Now, I work at MessageBird, so I could just dive in and start building. If you try this, you’ll need to request early access. But once you’re set up with a WhatsApp channel, you can log on to the Dashboard on the MessageBird website and get started.

Setting up your WhatsApp bot environment

The first thing I did was read the docs. I learned that, in order to get messages from the bot, I would have to use a webhook. This meant that my bot would need to be accessible from the internet. When building APIs like this, it's important to follow API versioning best practices for maintainability. Since I was just starting to code it, I decided to use ngrok. It creates a tunnel from the public internet to your dear localhost port 5007. Engage!

ngrok http 5007 -region eu -subdomain todobot

Creating your webhook and connecting Bird

Next, I needed to do a call to the Programmable Conversations API to create the webhook. It’s a POST to https://conversations.messagebird.com/v1/webhooks and it looks something like this:

func main() {// define the webhook json payload wh := struct { Events []string json:"events" ChannelID string json:"channelId" URL string json:"url" } { // we would like to be notified on the URL URL: "https://todobot.eu.ngrok.io/create-hook", // whenever a message gets created Events: []string{"message.created"}, }

b, _ := json.Marshal(wh) req, _ := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", bytes.NewBuffer(b)) req.Header.Set("Authorization", "AccessKey " + accessKey) req.Header.Set("Content-Type", "application/json") client := &http.Client{} client.Do(req) }

Sending responses and handling messages

Now, for the interesting part. Do a POST request to:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages to answer the request.

func respond(conversationID, responseBody string) error { u := fmt.Sprintf("https://conversations.messagebird.com/v1/conversations/%s/messages", conversationID)msg := message{ Content: content{ Text: responseBody, }, Type: "text", } var b bytes.Buffer json.NewEncoder(&b).Encode(msg) req, _ := http.NewRequest("POST", u, &b) req.Header.Set("Authorization", "AccessKey " + accessKey) req.Header.Set("Content-Type", "application/json") client := &http.Client{} _, err := client.Do(req) return err }

Archiving conversations and scaling your bot

Another important thing! You can archive conversations. In some applications, like CRMs, it’s important to keep track of certain interactions — to track the effectiveness of customer support employees, for example. The Conversations API lets you archive a conversation to "close" the topic. If the user/customer sends another message, the Conversations API will open a new topic automatically.

Managing conversation lifecycle Also. Doing PATCH request to https://conversations.messagebird.com/v1/conversations/{id} with the right status on the body allows you to archive the conversation with that id. We do this with the "bye" command:

case "bye": archiveConversation(whp.Conversation.ID) manager.close(whp.Conversation.ID) responseBody = "bye!"

Other news