Como construir um bot do WhatsApp para listas de tarefas usando a API de Conversas Programáveis do Bird

Pássaro

5 de fev. de 2020

WhatsApp

1 min read

Como construir um bot do WhatsApp para listas de tarefas usando a API de Conversas Programáveis do Bird

Principais Conclusões

    • A API de Conversas Programáveis do Bird unifica WhatsApp, Messenger e SMS em uma única camada de comunicação, simplificando o desenvolvimento de bots multicanal.

    • Você pode prototipar rapidamente um bot de lista de tarefas do WhatsApp usando webhooks e requisições POST simples.

    • Ferramentas como ngrok permitem expor seu servidor local para testes de webhook sem configuração de hospedagem complexa.

    • A API gerencia conversas através de múltiplos canais, permitindo uma base lógica para WhatsApp, WeChat e outros aplicativos.

    • Use o endpoint archiveConversation para fechar conversas ou “tópicos”, ideal para rastreamento de suporte ou fluxo de trabalho.

    • A lógica do bot pode gerenciar conversas concorrentes com segurança na memória com uma estrutura de dados simples.

    • O mesmo manipulador de webhook funciona em todos os canais—o Bird roteia automaticamente as respostas com base no ID da conversa de origem.

Destaques de Perguntas e Respostas

  • Quão difícil é construir um bot do WhatsApp usando a API do Bird?

    É surpreendentemente fácil. Com um webhook e algumas chamadas de API, você pode construir um bot funcional que lê e responde a mensagens em poucos minutos.

  • Eu preciso de uma configuração especial para receber mensagens?

    Sim — o bot deve ser acessível pela internet. Ferramentas como ngrok ajudam a criar um túnel seguro a partir da sua máquina local.

  • Posso usar a mesma base de código para diferentes aplicativos de mensagens?

    Absolutamente. A API de Conversas abstrai canais, então seu bot pode rodar no WhatsApp, WeChat ou Messenger usando a mesma lógica.

  • Como faço para fechar ou redefinir um bate-papo?

    Envie uma solicitação PATCH para o endpoint da conversa com o status apropriado para arquivá-la. Qualquer nova mensagem abre automaticamente uma nova conversa.

  • Onde posso encontrar código de exemplo?

    A: A demonstração completa — Wabot no GitHub — mostra a implementação de manipulação de mensagens, concorrência e arquivamento.

O Bird lançou recentemente Conversas Programáveis. Isso permite que as empresas misturem plataformas de comunicação como WhatsApp, Messenger e SMS em seus sistemas — usando uma única API.

Eu queria experimentar, então criei uma lista de tarefas no WhatsApp, porque quem não precisa de uma lista de tarefas automatizada para ajudar a organizar o dia? Pode parecer complicado, mas foi na verdade fácil, e eu gostaria de contar tudo sobre isso.

Agora, eu trabalho na MessageBird, então eu poderia simplesmente mergulhar e começar a construir. Se você tentar isso, precisará solicitar acesso antecipado. Mas uma vez que você esteja configurado com um canal do WhatsApp, pode fazer login no Painel no site da MessageBird e começar.

O Bird lançou recentemente Conversas Programáveis. Isso permite que as empresas misturem plataformas de comunicação como WhatsApp, Messenger e SMS em seus sistemas — usando uma única API.

Eu queria experimentar, então criei uma lista de tarefas no WhatsApp, porque quem não precisa de uma lista de tarefas automatizada para ajudar a organizar o dia? Pode parecer complicado, mas foi na verdade fácil, e eu gostaria de contar tudo sobre isso.

Agora, eu trabalho na MessageBird, então eu poderia simplesmente mergulhar e começar a construir. Se você tentar isso, precisará solicitar acesso antecipado. Mas uma vez que você esteja configurado com um canal do WhatsApp, pode fazer login no Painel no site da MessageBird e começar.

O Bird lançou recentemente Conversas Programáveis. Isso permite que as empresas misturem plataformas de comunicação como WhatsApp, Messenger e SMS em seus sistemas — usando uma única API.

Eu queria experimentar, então criei uma lista de tarefas no WhatsApp, porque quem não precisa de uma lista de tarefas automatizada para ajudar a organizar o dia? Pode parecer complicado, mas foi na verdade fácil, e eu gostaria de contar tudo sobre isso.

Agora, eu trabalho na MessageBird, então eu poderia simplesmente mergulhar e começar a construir. Se você tentar isso, precisará solicitar acesso antecipado. Mas uma vez que você esteja configurado com um canal do WhatsApp, pode fazer login no Painel no site da MessageBird e começar.

Configurando o ambiente do seu bot do WhatsApp

A primeira coisa que fiz foi ler a documentação. Aprendi que, para receber mensagens do bot, eu teria que usar um webhook. Isso significava que meu bot precisaria ser acessível pela internet. Ao construir APIs como essa, é importante seguir as melhores práticas de versionamento de API para manutenibilidade. Como eu estava começando a codificá-lo, decidi usar ngrok. Ele cria um túnel da internet pública para o seu querido localhost na porta 5007. Engage!

ngrok http 5007 -region eu -subdomain todobot

A primeira coisa que fiz foi ler a documentação. Aprendi que, para receber mensagens do bot, eu teria que usar um webhook. Isso significava que meu bot precisaria ser acessível pela internet. Ao construir APIs como essa, é importante seguir as melhores práticas de versionamento de API para manutenibilidade. Como eu estava começando a codificá-lo, decidi usar ngrok. Ele cria um túnel da internet pública para o seu querido localhost na porta 5007. Engage!

ngrok http 5007 -region eu -subdomain todobot

A primeira coisa que fiz foi ler a documentação. Aprendi que, para receber mensagens do bot, eu teria que usar um webhook. Isso significava que meu bot precisaria ser acessível pela internet. Ao construir APIs como essa, é importante seguir as melhores práticas de versionamento de API para manutenibilidade. Como eu estava começando a codificá-lo, decidi usar ngrok. Ele cria um túnel da internet pública para o seu querido localhost na porta 5007. Engage!

ngrok http 5007 -region eu -subdomain todobot

Criando seu webhook e conectando o Bird

Em seguida, eu precisava fazer uma chamada para a API de Conversas Programáveis para criar o webhook. É um POST para https://conversations.messagebird.com/v1/webhooks e parece algo assim:

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"},
    // on the WhatsApp channel with ID
    ChannelID: "23a780701b8849f7b974d8620a89a279",
  }
  
  // encode the payload to json
  var b bytes.Buffer
  err := json.NewEncoder(&b).Encode(&wh)
  if err != nil {
    panic(err)
  }
  
  // create the http request and set authorization header
  req, err := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json") // fire the http request
  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
         panic(err)
  }
  defer resp.Body.Close()// is everything ok?
  body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode >= http.StatusBadRequest {
    panic(fmt.Errorf("Bad response code from api when trying to create webhook: %s. Body: %s", resp.Status, string(body)))
  } else {
    log.Println("All good. response body: ", string(body))
  }
}


Ótimo. Agora a API de Conversas vai fazer uma requisição POST para:

https://todobot.eu.ngrok.io/create-hook sempre que uma nova mensagem for criada no canal do WhatsApp que você configurou anteriormente.

Este é o aspecto de um payload de webhook:

{
  "conversation":{
    "id":"55c66895c22a40e39a8e6bd321ec192e",
    "contactId":"db4dd5087fb343738e968a323f640576",
    "status":"active",
    "createdDatetime":"2018-08-17T10:14:14Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z",
    "lastReceivedDatetime":"2018-08-17T14:30:31.898389294Z"
  },
  "message":{
    "id":"ddb150149e2c4036a48f581544e22cfe",
    "conversationId":"55c66895c22a40e39a8e6bd321ec192e",
    "channelId":"23a780701b8849f7b974d8620a89a279",
    "status":"received",
    "type":"text",
    "direction":"received",
    "content":{
      "text":"add buy milk"
    },
    "createdDatetime":"2018-08-17T14:30:31.898389294Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z"
  },
  "type":"message.created"
}


Queremos responder a essas mensagens. Vamos começar fazendo eco, o que você acha?

// define the structs where we'll parse the webhook payload into
type whPayload struct {
  Conversation conversation `json:"conversation"`
  Message      message      `json:"message"`
  Type         string       `json:"type"`
}

type message struct {
  ID        string  `json:"id"`
  Direction string  `json:"direction"`
  Type      string  `json:"type"`
  Content   content `json:"content"`
}

type content struct {
  Text string `json:"text"`
}

type conversation struct {
  ID string `json:"id"`
}

func main() {
  http.HandleFunc("/create-hook", createHookHandler)
  log.Fatal(http.ListenAndServe(*httpListenAddress, nil))
}
// createHookHandler is an http handler that will handle webhook requests
func createHookHandler(w http.ResponseWriter, r *http.Request) {
  // parse the incoming json payload
  whp := &whPayload{}
  err := json.NewDecoder(r.Body).Decode(whp)
  if err != nil {
    log.Println("Err: got weird body on the webhook")
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")
    return
  } 
  if whp.Message.Direction != "received" {
    // you will get *all* messages on the webhook. Even the ones this bot sends to the channel. We don't want to answer those.
    fmt.Fprintf(w, "ok")
    return
  } // echo: respond what we get
  err = respond(whp.Conversation.ID, whp.Message.Content.Text)
  
  if err != nil {
    log.Println("Err: ", err)
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")return
  }
  w.WriteHeader(http.StatusOK)
  fmt.Fprintf(w, "ok")
}

Em seguida, eu precisava fazer uma chamada para a API de Conversas Programáveis para criar o webhook. É um POST para https://conversations.messagebird.com/v1/webhooks e parece algo assim:

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"},
    // on the WhatsApp channel with ID
    ChannelID: "23a780701b8849f7b974d8620a89a279",
  }
  
  // encode the payload to json
  var b bytes.Buffer
  err := json.NewEncoder(&b).Encode(&wh)
  if err != nil {
    panic(err)
  }
  
  // create the http request and set authorization header
  req, err := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json") // fire the http request
  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
         panic(err)
  }
  defer resp.Body.Close()// is everything ok?
  body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode >= http.StatusBadRequest {
    panic(fmt.Errorf("Bad response code from api when trying to create webhook: %s. Body: %s", resp.Status, string(body)))
  } else {
    log.Println("All good. response body: ", string(body))
  }
}


Ótimo. Agora a API de Conversas vai fazer uma requisição POST para:

https://todobot.eu.ngrok.io/create-hook sempre que uma nova mensagem for criada no canal do WhatsApp que você configurou anteriormente.

Este é o aspecto de um payload de webhook:

{
  "conversation":{
    "id":"55c66895c22a40e39a8e6bd321ec192e",
    "contactId":"db4dd5087fb343738e968a323f640576",
    "status":"active",
    "createdDatetime":"2018-08-17T10:14:14Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z",
    "lastReceivedDatetime":"2018-08-17T14:30:31.898389294Z"
  },
  "message":{
    "id":"ddb150149e2c4036a48f581544e22cfe",
    "conversationId":"55c66895c22a40e39a8e6bd321ec192e",
    "channelId":"23a780701b8849f7b974d8620a89a279",
    "status":"received",
    "type":"text",
    "direction":"received",
    "content":{
      "text":"add buy milk"
    },
    "createdDatetime":"2018-08-17T14:30:31.898389294Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z"
  },
  "type":"message.created"
}


Queremos responder a essas mensagens. Vamos começar fazendo eco, o que você acha?

// define the structs where we'll parse the webhook payload into
type whPayload struct {
  Conversation conversation `json:"conversation"`
  Message      message      `json:"message"`
  Type         string       `json:"type"`
}

type message struct {
  ID        string  `json:"id"`
  Direction string  `json:"direction"`
  Type      string  `json:"type"`
  Content   content `json:"content"`
}

type content struct {
  Text string `json:"text"`
}

type conversation struct {
  ID string `json:"id"`
}

func main() {
  http.HandleFunc("/create-hook", createHookHandler)
  log.Fatal(http.ListenAndServe(*httpListenAddress, nil))
}
// createHookHandler is an http handler that will handle webhook requests
func createHookHandler(w http.ResponseWriter, r *http.Request) {
  // parse the incoming json payload
  whp := &whPayload{}
  err := json.NewDecoder(r.Body).Decode(whp)
  if err != nil {
    log.Println("Err: got weird body on the webhook")
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")
    return
  } 
  if whp.Message.Direction != "received" {
    // you will get *all* messages on the webhook. Even the ones this bot sends to the channel. We don't want to answer those.
    fmt.Fprintf(w, "ok")
    return
  } // echo: respond what we get
  err = respond(whp.Conversation.ID, whp.Message.Content.Text)
  
  if err != nil {
    log.Println("Err: ", err)
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")return
  }
  w.WriteHeader(http.StatusOK)
  fmt.Fprintf(w, "ok")
}

Em seguida, eu precisava fazer uma chamada para a API de Conversas Programáveis para criar o webhook. É um POST para https://conversations.messagebird.com/v1/webhooks e parece algo assim:

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"},
    // on the WhatsApp channel with ID
    ChannelID: "23a780701b8849f7b974d8620a89a279",
  }
  
  // encode the payload to json
  var b bytes.Buffer
  err := json.NewEncoder(&b).Encode(&wh)
  if err != nil {
    panic(err)
  }
  
  // create the http request and set authorization header
  req, err := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json") // fire the http request
  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
         panic(err)
  }
  defer resp.Body.Close()// is everything ok?
  body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode >= http.StatusBadRequest {
    panic(fmt.Errorf("Bad response code from api when trying to create webhook: %s. Body: %s", resp.Status, string(body)))
  } else {
    log.Println("All good. response body: ", string(body))
  }
}


Ótimo. Agora a API de Conversas vai fazer uma requisição POST para:

https://todobot.eu.ngrok.io/create-hook sempre que uma nova mensagem for criada no canal do WhatsApp que você configurou anteriormente.

Este é o aspecto de um payload de webhook:

{
  "conversation":{
    "id":"55c66895c22a40e39a8e6bd321ec192e",
    "contactId":"db4dd5087fb343738e968a323f640576",
    "status":"active",
    "createdDatetime":"2018-08-17T10:14:14Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z",
    "lastReceivedDatetime":"2018-08-17T14:30:31.898389294Z"
  },
  "message":{
    "id":"ddb150149e2c4036a48f581544e22cfe",
    "conversationId":"55c66895c22a40e39a8e6bd321ec192e",
    "channelId":"23a780701b8849f7b974d8620a89a279",
    "status":"received",
    "type":"text",
    "direction":"received",
    "content":{
      "text":"add buy milk"
    },
    "createdDatetime":"2018-08-17T14:30:31.898389294Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z"
  },
  "type":"message.created"
}


Queremos responder a essas mensagens. Vamos começar fazendo eco, o que você acha?

// define the structs where we'll parse the webhook payload into
type whPayload struct {
  Conversation conversation `json:"conversation"`
  Message      message      `json:"message"`
  Type         string       `json:"type"`
}

type message struct {
  ID        string  `json:"id"`
  Direction string  `json:"direction"`
  Type      string  `json:"type"`
  Content   content `json:"content"`
}

type content struct {
  Text string `json:"text"`
}

type conversation struct {
  ID string `json:"id"`
}

func main() {
  http.HandleFunc("/create-hook", createHookHandler)
  log.Fatal(http.ListenAndServe(*httpListenAddress, nil))
}
// createHookHandler is an http handler that will handle webhook requests
func createHookHandler(w http.ResponseWriter, r *http.Request) {
  // parse the incoming json payload
  whp := &whPayload{}
  err := json.NewDecoder(r.Body).Decode(whp)
  if err != nil {
    log.Println("Err: got weird body on the webhook")
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")
    return
  } 
  if whp.Message.Direction != "received" {
    // you will get *all* messages on the webhook. Even the ones this bot sends to the channel. We don't want to answer those.
    fmt.Fprintf(w, "ok")
    return
  } // echo: respond what we get
  err = respond(whp.Conversation.ID, whp.Message.Content.Text)
  
  if err != nil {
    log.Println("Err: ", err)
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")return
  }
  w.WriteHeader(http.StatusOK)
  fmt.Fprintf(w, "ok")
}

Enviando respostas e lidando com mensagens

Agora, para a parte interessante. Faça uma requisição POST para:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages para responder à solicitação.

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
  err := json.NewEncoder(&b).Encode(&msg)
  if err != nil {
    return fmt.Errorf("Error encoding buffer: %v", err)
  }
  req, err := http.NewRequest("POST", u.String(), &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json")client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    return err
  }
  defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode != http.StatusCreated {
    return fmt.Errorf("Bad response code from api when trying to create message: %s. Body: %s", resp.Status, string(body))
  }
  log.Println("All good. Response body: ", string(body))
  return nil
}

Pronto. Isso é tudo que você precisa para criar um bot que age como uma criança de 5 anos.


Aqui está o porquê de usar a API de Conversas da Bird tornar o desenvolvimento de bots para WhatsApp rápido e escalável:

Recurso

O que resolve

ID de conversa unificado

Manter um único tópico entre aplicativos como WhatsApp, WeChat, Messenger

API única para todos os canais

Reutilizar lógica do bot sem reescrever para cada plataforma

Automação impulsionada por Webhook

Tratamento rápido de respostas sem polling

Arquivar + reabrir tópicos

Organizar o histórico de suporte e fluxos de trabalho

Estrutura segura para concorrência

Gerenciar múltiplas conversas ao mesmo tempo de forma confiável


Agora, vamos avançar para construir toda a lista de tarefas. Primeiro, modifique um pouco a função createHookHandler para que chame a nova função handleMessage em vez de respond.

func createHookHandler(w http.ResponseWriter, r *http.Request) {
  ...
  err = handleMessage(whp)
  ...
}


handle irá analisar as mensagens de forma simplista, fazer algum trabalho e escolher a resposta. Vamos olhar o comando "add":

func handleMessage(whp *whPayload) error {
  // every conversation has a todo list
  list := manager.fetch(whp.Conversation.ID)
  // parse the command from the message body: it's the first word
  text := whp.Message.Content.Text
  text = regexp.MustCompile(" +").ReplaceAllString(text, " ")
  parts := strings.Split(text, " ")
  command := strings.ToLower(parts[0])
  // default message
  responseBody := "I don't understand. Type 'help' to get help."
  switch command {
  ...
  case "add":
    if len(parts) < 2 {
           return respond(whp.Conversation.ID, "err... the 'add' command needs a second param: the todo item you want to save. Something like 'add buy milk'.")
    }
    // get the item from the message body
    item := strings.Join(parts[1:], " ")list.add(item)
    responseBody = "added."
  ...
  return respond(whp.Conversation.ID, responseBody)
}

Aqui, nós configuramos:list := manager.fetch(whp.Conversation.ID). Basicamente, "manager" é um mapa seguro para concorrência que mapeia IDs de conversa para listas de tarefas.

Uma lista de tarefas é um slice de string seguro para concorrência. Tudo na memória!

Agora, para a parte interessante. Faça uma requisição POST para:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages para responder à solicitação.

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
  err := json.NewEncoder(&b).Encode(&msg)
  if err != nil {
    return fmt.Errorf("Error encoding buffer: %v", err)
  }
  req, err := http.NewRequest("POST", u.String(), &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json")client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    return err
  }
  defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode != http.StatusCreated {
    return fmt.Errorf("Bad response code from api when trying to create message: %s. Body: %s", resp.Status, string(body))
  }
  log.Println("All good. Response body: ", string(body))
  return nil
}

Pronto. Isso é tudo que você precisa para criar um bot que age como uma criança de 5 anos.


Aqui está o porquê de usar a API de Conversas da Bird tornar o desenvolvimento de bots para WhatsApp rápido e escalável:

Recurso

O que resolve

ID de conversa unificado

Manter um único tópico entre aplicativos como WhatsApp, WeChat, Messenger

API única para todos os canais

Reutilizar lógica do bot sem reescrever para cada plataforma

Automação impulsionada por Webhook

Tratamento rápido de respostas sem polling

Arquivar + reabrir tópicos

Organizar o histórico de suporte e fluxos de trabalho

Estrutura segura para concorrência

Gerenciar múltiplas conversas ao mesmo tempo de forma confiável


Agora, vamos avançar para construir toda a lista de tarefas. Primeiro, modifique um pouco a função createHookHandler para que chame a nova função handleMessage em vez de respond.

func createHookHandler(w http.ResponseWriter, r *http.Request) {
  ...
  err = handleMessage(whp)
  ...
}


handle irá analisar as mensagens de forma simplista, fazer algum trabalho e escolher a resposta. Vamos olhar o comando "add":

func handleMessage(whp *whPayload) error {
  // every conversation has a todo list
  list := manager.fetch(whp.Conversation.ID)
  // parse the command from the message body: it's the first word
  text := whp.Message.Content.Text
  text = regexp.MustCompile(" +").ReplaceAllString(text, " ")
  parts := strings.Split(text, " ")
  command := strings.ToLower(parts[0])
  // default message
  responseBody := "I don't understand. Type 'help' to get help."
  switch command {
  ...
  case "add":
    if len(parts) < 2 {
           return respond(whp.Conversation.ID, "err... the 'add' command needs a second param: the todo item you want to save. Something like 'add buy milk'.")
    }
    // get the item from the message body
    item := strings.Join(parts[1:], " ")list.add(item)
    responseBody = "added."
  ...
  return respond(whp.Conversation.ID, responseBody)
}

Aqui, nós configuramos:list := manager.fetch(whp.Conversation.ID). Basicamente, "manager" é um mapa seguro para concorrência que mapeia IDs de conversa para listas de tarefas.

Uma lista de tarefas é um slice de string seguro para concorrência. Tudo na memória!

Agora, para a parte interessante. Faça uma requisição POST para:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages para responder à solicitação.

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
  err := json.NewEncoder(&b).Encode(&msg)
  if err != nil {
    return fmt.Errorf("Error encoding buffer: %v", err)
  }
  req, err := http.NewRequest("POST", u.String(), &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json")client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    return err
  }
  defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode != http.StatusCreated {
    return fmt.Errorf("Bad response code from api when trying to create message: %s. Body: %s", resp.Status, string(body))
  }
  log.Println("All good. Response body: ", string(body))
  return nil
}

Pronto. Isso é tudo que você precisa para criar um bot que age como uma criança de 5 anos.


Aqui está o porquê de usar a API de Conversas da Bird tornar o desenvolvimento de bots para WhatsApp rápido e escalável:

Recurso

O que resolve

ID de conversa unificado

Manter um único tópico entre aplicativos como WhatsApp, WeChat, Messenger

API única para todos os canais

Reutilizar lógica do bot sem reescrever para cada plataforma

Automação impulsionada por Webhook

Tratamento rápido de respostas sem polling

Arquivar + reabrir tópicos

Organizar o histórico de suporte e fluxos de trabalho

Estrutura segura para concorrência

Gerenciar múltiplas conversas ao mesmo tempo de forma confiável


Agora, vamos avançar para construir toda a lista de tarefas. Primeiro, modifique um pouco a função createHookHandler para que chame a nova função handleMessage em vez de respond.

func createHookHandler(w http.ResponseWriter, r *http.Request) {
  ...
  err = handleMessage(whp)
  ...
}


handle irá analisar as mensagens de forma simplista, fazer algum trabalho e escolher a resposta. Vamos olhar o comando "add":

func handleMessage(whp *whPayload) error {
  // every conversation has a todo list
  list := manager.fetch(whp.Conversation.ID)
  // parse the command from the message body: it's the first word
  text := whp.Message.Content.Text
  text = regexp.MustCompile(" +").ReplaceAllString(text, " ")
  parts := strings.Split(text, " ")
  command := strings.ToLower(parts[0])
  // default message
  responseBody := "I don't understand. Type 'help' to get help."
  switch command {
  ...
  case "add":
    if len(parts) < 2 {
           return respond(whp.Conversation.ID, "err... the 'add' command needs a second param: the todo item you want to save. Something like 'add buy milk'.")
    }
    // get the item from the message body
    item := strings.Join(parts[1:], " ")list.add(item)
    responseBody = "added."
  ...
  return respond(whp.Conversation.ID, responseBody)
}

Aqui, nós configuramos:list := manager.fetch(whp.Conversation.ID). Basicamente, "manager" é um mapa seguro para concorrência que mapeia IDs de conversa para listas de tarefas.

Uma lista de tarefas é um slice de string seguro para concorrência. Tudo na memória!

Arquivando conversas e escalando seu bot

Outra coisa importante! Você pode arquivar conversas. Em alguns aplicativos, como CRMs, é importante acompanhar certas interações - para acompanhar a eficácia dos funcionários de suporte ao cliente, por exemplo. A API de Conversas permite que você arquive uma conversa para “fechar” o tópico. Se o usuário/cliente enviar outra mensagem, a API de Conversas abrirá automaticamente um novo tópico.

Gerenciando o ciclo de vida da conversa

Além disso. Fazer uma solicitação PATCH para https://conversations.messagebird.com/v1/conversations/{id} com o status correto no corpo permite que você arquive a conversa com aquele id. Fazemos isso com o comando “bye”:

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

archiveConversation fará a solicitação PATCH e manager.close(whp.Conversation.ID) removerá a conversa da lista de afazeres.

Mas ei, Conversas Programáveis é uma solução omnichannel. E se você quisesse reutilizar o código do bot para uma plataforma diferente, como WeChat? Essa abordagem multicanal faz parte da estratégia de desvio de consultas para canais de menor custo. Como você faria isso?

Crie um novo webhook para direcionar aquele canal! Um webhook que envia solicitações para a mesma https://todobot.eu.ngrok.io/create-hook url que usamos para o WhatsApp!

Isso funcionará porque o código do manipulador sempre usa o conversationID do payload do webhook para responder às mensagens em vez de um channelID codificado na aplicação. A API de Conversas do MessageBird determinará automaticamente o canal para a conversa e enviará sua mensagem.

Você quer construir seu próprio bot? Dê uma olhada no código completo no Github: Wabot no Github, solicite acesso antecipado ao WhatsApp visitando a página do WhatsApp e clicando no botão Contatar Vendas para preencher o formulário. Boa sorte com o bot!

Outra coisa importante! Você pode arquivar conversas. Em alguns aplicativos, como CRMs, é importante acompanhar certas interações - para acompanhar a eficácia dos funcionários de suporte ao cliente, por exemplo. A API de Conversas permite que você arquive uma conversa para “fechar” o tópico. Se o usuário/cliente enviar outra mensagem, a API de Conversas abrirá automaticamente um novo tópico.

Gerenciando o ciclo de vida da conversa

Além disso. Fazer uma solicitação PATCH para https://conversations.messagebird.com/v1/conversations/{id} com o status correto no corpo permite que você arquive a conversa com aquele id. Fazemos isso com o comando “bye”:

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

archiveConversation fará a solicitação PATCH e manager.close(whp.Conversation.ID) removerá a conversa da lista de afazeres.

Mas ei, Conversas Programáveis é uma solução omnichannel. E se você quisesse reutilizar o código do bot para uma plataforma diferente, como WeChat? Essa abordagem multicanal faz parte da estratégia de desvio de consultas para canais de menor custo. Como você faria isso?

Crie um novo webhook para direcionar aquele canal! Um webhook que envia solicitações para a mesma https://todobot.eu.ngrok.io/create-hook url que usamos para o WhatsApp!

Isso funcionará porque o código do manipulador sempre usa o conversationID do payload do webhook para responder às mensagens em vez de um channelID codificado na aplicação. A API de Conversas do MessageBird determinará automaticamente o canal para a conversa e enviará sua mensagem.

Você quer construir seu próprio bot? Dê uma olhada no código completo no Github: Wabot no Github, solicite acesso antecipado ao WhatsApp visitando a página do WhatsApp e clicando no botão Contatar Vendas para preencher o formulário. Boa sorte com o bot!

Outra coisa importante! Você pode arquivar conversas. Em alguns aplicativos, como CRMs, é importante acompanhar certas interações - para acompanhar a eficácia dos funcionários de suporte ao cliente, por exemplo. A API de Conversas permite que você arquive uma conversa para “fechar” o tópico. Se o usuário/cliente enviar outra mensagem, a API de Conversas abrirá automaticamente um novo tópico.

Gerenciando o ciclo de vida da conversa

Além disso. Fazer uma solicitação PATCH para https://conversations.messagebird.com/v1/conversations/{id} com o status correto no corpo permite que você arquive a conversa com aquele id. Fazemos isso com o comando “bye”:

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

archiveConversation fará a solicitação PATCH e manager.close(whp.Conversation.ID) removerá a conversa da lista de afazeres.

Mas ei, Conversas Programáveis é uma solução omnichannel. E se você quisesse reutilizar o código do bot para uma plataforma diferente, como WeChat? Essa abordagem multicanal faz parte da estratégia de desvio de consultas para canais de menor custo. Como você faria isso?

Crie um novo webhook para direcionar aquele canal! Um webhook que envia solicitações para a mesma https://todobot.eu.ngrok.io/create-hook url que usamos para o WhatsApp!

Isso funcionará porque o código do manipulador sempre usa o conversationID do payload do webhook para responder às mensagens em vez de um channelID codificado na aplicação. A API de Conversas do MessageBird determinará automaticamente o canal para a conversa e enviará sua mensagem.

Você quer construir seu próprio bot? Dê uma olhada no código completo no Github: Wabot no Github, solicite acesso antecipado ao WhatsApp visitando a página do WhatsApp e clicando no botão Contatar Vendas para preencher o formulário. Boa sorte com o bot!

Outras notícias

Leia mais desta categoria

A person is standing at a desk while typing on a laptop.

A plataforma completa nativa de IA que escalará com o seu negócio.

© 2025 Pássaro

A person is standing at a desk while typing on a laptop.

A plataforma completa nativa de IA que escalará com o seu negócio.

© 2025 Pássaro