Crie um fluxo de chat usando inúmeras chamadas de API em conjunto

Aprenda a criar um fluxo de chat com o Zenvia Flow para permitir ao cliente agendar atendimentos de forma simplificada.

Neste tutorial, utilizaremos o Zenvia Flow para criar um fluxo de chat, permitindo ao cliente agendar um atendimento. Com isso feito, um atendente poderá entrar em contato com o usuário via Whatsapp no futuro. Este fluxo conterá chamadas a variadas APIs, uma destas será desenvolvida por você e será capaz de armazenar informações do usuário em uma base de dados e de permitir a consulta para verificar a existência deste usuário na mesma base de dados. Outra API que consumiremos é a de 2FA (Two Factor Authentication) da Zenvia envia que será usada para confirmar o número de telefone do usuário.

Primeiros passos

1- O primeiro passo é criar uma conta na plataforma principal da Zenvia.  É nela que criaremos o nosso fluxo. Na sequência, é preciso preencher as informações solicitadas e clicar em “CRIAR“. Em seguida, você deve confirmar o número de celular e o endereço de e-mail para ter acesso ao painel.

2- Depois disso, é necessário criar uma conta na plataforma de voz da Zenvia. Entre aqui e clique em “CRIAR CONTA”. Na sequência, confirme o número de celular e o endereço de e-mail acessar o painel. Após confirmar suas informações é possível acessar o painel e adquirir o Access Token, a fim de autenticar as requisições à API por meio dos headers da requisição. Você precisará desta informação mais tarde.

Criando o fluxo de Web Chat na Zenvia

Agora, desenvolveremos o fluxo de Web Chat que poderá ser integrado ao seu site facilmente, pois a Zenvia gera um embed que pode ser integrado ao HTML da sua página. A Zenvia também permite a personalização do visual do chat, porém neste tutorial iremos criá-lo com os templates visuais já disponibilizados. Para isso, siga o fluxo a seguir caso já tenha criado sua conta na plataforma principal da Zenvia e esteja autenticado:

Agora que seu fluxo está criado e configurado, podemos incrementá-lo com chamadas às APIs. Primeiramente, precisamos desenvolver a aplicação responsável por armazenar os agendamentos. Para isso, construiremos uma API em Node.js.

Antes de tudo, devemos solicitar o número do WhatsApp do usuário, que iremos utilizar posteriormente.

Dessa forma o número ficará salvo na variável #{tel} dentro do fluxo e podemos utilizá-lo no futuro.

Construindo a API Node.js

1- Instale o Node.js no seu computador (de preferência a versão LTS);

1.1- opcional – Instale o yarn. O Node.js possui um gerenciador de pacotes padrão chamado npm (Node Package Manager), porém, há um gerenciador diferente chamado yarn. No restante do artigo, apresentaremos as opções de instalação para ambos gerenciadores de pacote como no passo a seguir.

2- Inicie o projeto criando o package.json com o seguinte comando no terminal:

npm init -y

yarn init -y

3- Instale o ts-nodets-node-dev e o typescript como dependências de desenvolvimento:

npm i ts-node ts-node-dev typescript -D

yarn add ts-node ts-node-dev typescript -D

3.1 – Instale o arquivo de configuração do typescript:

npx typescript --init

4- Crie um arquivo src/server.ts para testarmos a aplicação:

console.log('Hello World!')

5- Abra o arquivo package.json e insira o script para iniciar o servidor, assim como na área grifada em cinza:

{
  "name": "zenvia-flow-api",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "ts-node-dev --transpile-only --ignore-watch node_modules --respawn src/server.ts"
  },
  "devDependencies": {
    "ts-node": "^9.1.1",
    "ts-node-d": "^1.1.1",
    "typescript": "^4.1.3"
  }
}

5.1- Sempre que você quiser executar a aplicação, só precisa executar o seguinte no terminal:

npm run dev

yarn dev

6- Instale o Express para criarmos nossa API:

npm i express && npm i --save-dev @types/express

yarn add express && yarn add @types/express -D

7- Vamos começar criando o nosso banco de dados que armazenará as informações dos inadimplentes. Para fins didáticos, vamos utilizar o banco de dados SQLite, pois ele não necessita de instalação e o banco fica salvo em apenas um arquivo. Para manusear o banco de dados vamos utilizar o Prisma, um ORM (Object Relational Mapper) muito útil e prático para Node.js e TypeScript, permitindo que alteremos o banco de dados mudando apenas uma linha de código. Instale as dependências do prisma prisma e @prisma/client e inicialize o prisma:

npm install prisma @prisma/client

yarn add prisma @prisma/client && npx prisma init

A inicialização do prisma gerará um arquivo prisma/schema.prisma. É nele que iremos esquematizar nosso banco de dados.

8- Arquitete o banco de dados no arquivo prisma/schema.prisma:

datasource db {
 provider = "sqlite"
 url   = "file:./dev.db"
}

generator client {
 provider = "prisma-client-js"
}

model Pessoa {
 id      Int      @id @default(autoincrement())
 nome    String
 whatsapp String
 Atendimento Atendimento[]
}

model Atendimento {
 id             Int         @id @default(autoincrement())
 Pessoa      Pessoa      @relation(fields: [pessoaId], references: [id])
 dividendoId    Int
}  

9- Execute a criação do banco de dados:

npx prisma migrate dev --name init --preview-feature

Assim, o arquivo do seu banco de dados será criado prisma/dev.db.

10- Volte para o arquivo src/server.ts. Ele será o nosso arquivo de configuração do servidor para criação da nossa API:

import express, { json } from 'express'

// Inicializa o express e define uma porta
const app = express()
const PORT = 3000

// Indica para o express usar o JSON parsing do body-parser
app.use(json())

// Inicia o express na porta definida anteriormente
app.listen(PORT, () => console.log(`Servidor rodando na porta ${PORT}`))

11- Crie a o arquivo src/findPessoaByWhatsapp com a função que encontrará a pessoa pelo número de WhatsApp. Também crie a roda no src/server.ts:

// src/findPessoaByWhatsapp.ts
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

export const findPessoaByWhatsapp = async (whatsapp: string) => {
 return prisma.pessoa.findUnique({
  where: {
   whatsapp,
  },
 })
}  
// src/server.ts
import express, { Request, Response, json } from 'express'
import { findPessoaByWhatsapp } from './functions/findPessoaByWhatsapp'

// Inicializa o express e define uma porta
const app = express()
const PORT = 3000

// Indica para o express usar o JSON parsing do body-parser
app.use(json())

app.get('/pessoa', async (request: Request, response: Response) => {
 // Armazena os parâmetros passados pelo Zenvia Flow em variáveis
 const { whatsapp } = request.query

 // Verifica se as variáveis não são strings
 if (typeof whatsapp !== 'string') {
  return response.status(400).end() // Responde quem solicitou nosso webhook com status 400
 } else {
  try {
   // Chama a função que busca a Pessoa pelo número de WhatsApp banco de dados
   return response.status(201).json({ pessoa: await findPessoaByWhatsapp(whatsapp) }) // Responde quem solicitou nosso webhook com status 200
  } catch (error) {
   return response.status(500).end() // Responde quem solicitou nosso webhook com status 500 de erro
  }
 }
})

// Inicia o express na porta definida anteriormente
app.listen(PORT, () => console.log(`Servidor rodando na porta ${PORT}`))
     

12- Crie o arquivo src/savePessoa com a função que salvará os dados da pessoa no banco de dados:

// src/server.ts
import express, { Request, Response, json } from 'express'
import { findPessoaByWhatsapp } from './functions/findPessoaByWhatsapp'

// Inicializa o express e define uma porta
const app = express()
const PORT = 3000

// Indica para o express usar o JSON parsing do body-parser
app.use(json())

app.get('/pessoa', async (request: Request, response: Response) => {
 // Armazena os parâmetros passados pelo Zenvia Flow em variáveis
 const { whatsapp } = request.query

 // Verifica se as variáveis não são strings
 if (typeof whatsapp !== 'string') {
  return response.status(400).end() // Responde quem solicitou nosso webhook com status 400
 } else {
  try {
   // Chama a função que busca a Pessoa pelo número de WhatsApp banco de dados
   return response.status(201).json({ pessoa: await findPessoaByWhatsapp(whatsapp) }) // Responde quem solicitou nosso webhook com status 200
  } catch (error) {
   return response.status(500).end() // Responde quem solicitou nosso webhook com status 500 de erro
  }
 }
})

// Inicia o express na porta definida anteriormente
app.listen(PORT, () => console.log(`Servidor rodando na porta ${PORT}`))
// src/server.ts
import express, { Request, Response, json } from 'express'
import { findPessoaByWhatsapp } from './functions/findPessoaByWhatsapp'
import { savePessoa } from './functions/savePessoa'

// Inicializa o express e define uma porta
const app = express()
const PORT = 3000

// Indica para o express usar o JSON parsing do body-parser
app.use(json())

app.get('/pessoa', async (request: Request, response: Response) => {
 // ...
})


app.post('/pessoa', async (request: Request, response: Response) => {
 // Armazena os parâmetros passados pelo Zenvia Flow em variáveis
 const { nome, whatsapp } = request.query

 // Verifica se as variáveis não são strings
 if (typeof nome !== 'string' || typeof whatsapp !== 'string') {
  return response.status(400).end() // Responde quem solicitou nosso webhook com status 400
 } else {
  try {
   // Chama a função que busca a Pessoa pelo número de WhatsApp banco de dados
   return response.status(201).json({ pessoa: await savePessoa({ nome, whatsapp }) }) // Responde quem solicitou nosso webhook com status 200
  } catch (error) {
   return response.status(500).end() // Responde quem solicitou nosso webhook com status 500 de erro
  }
 }
})

// Inicia o express na porta definida anteriormente
app.listen(PORT, () => console.log(`Servidor rodando na porta ${PORT}`))

13- Crie o arquivo src/saveAgendamento com a função que salvará a o agendamento no banco de dados:

// src/saveAgendamento.ts
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

export const saveAgendamento = async (whatsapp: string) => {
 const pessoa = await prisma.pessoa.findUnique({
  where: {
   whatsapp,
  },
 })
 if (pessoa) {
  return prisma.atendimento.create({
   data: { pessoaId: pessoa.id },
  })
 } else {
  throw new Error('Pessoa não encontrada!')
 }
}
// src/server.ts

// ...
 
app.post('/agendamento', async (request: Request, response: Response) => {
 const { whatsapp } = request.body

 try {
  return response.status(201).json({ agendamento: await saveAgendamento(whatsapp) }) // Responde quem solicitou nosso webhook com status 200
 } catch (error) {
  return response.status(500).end() // Responde quem solicitou nosso webhook com status 500 de erro
 }
})

// Inicia o express na porta definida anteriormente
app.listen(PORT, () => console.log(`Servidor rodando na porta ${PORT}`))    

Como essa API está rodando em nossa máquina local, precisamos expô-la para receber as requisições do fluxo Zenvia. Para isso, utilizaremos o ngrok. Se você tiver a intenção de subir sua aplicação em algum serviço de hospedagem, o procedimento a seguir não serve para você.

Para criar o link que o fluxo enviará para a requisição usaremos o ngrok, também para expor nossa porta 3000 (porta em que a aplicação está rodando) e ainda criar um link público para que as requisições http possam ser enviadas diretamente à nossa aplicação local.

Se a sua aplicação estivesse hospedada em algum site, não teríamos a necessidade da criação de um link público, pois já haveria um.

Faça login no site, baixe a versão para Windows, extraia o zip, execute a aplicação (terminal será aberto), autentique-se digitando ngrok authtoken SEU_TOKEN (seu token está na primeira tela do seu dashboard) e exponha a porta da aplicação (3000) digitando ngrok http 3000.

Após expor a porta da sua aplicação, copie o link que aparecerá no terminal, volte para o último nó do fluxo e cole o link copiado do terminal no site.

Para utilizar sua API no fluxo, você precisa apenas usar este link gerado e colocar o endpoint ao final (algo semelhante a isso: http://396e5b25cf84.ngrok.io/pessoa):

Lembre-se que ao fechar o ngrok e expor a porta novamente, será gerado um novo link, então você deve ir ao fluxo e atualizar o link que estiver lá.

Voltando ao fluxo

Com a nossa API, que vai armazenar as informações e enviar a primeira mensagem no WhatsApp do cliente, para confirmar o agendamento, podemos voltar ao fluxo para integrar tudo.

1- Comece criando a chamada à nossa API, que irá fazer a busca no banco de dados, para sabermos se o usuário já existe:

Aqui estamos acessando o endpoint /pessoa com o método GET e passando o número informado pelo usuário através do parâmetro de consulta whatsapp, que irá retornar as informações da pessoa (caso ela já exista no banco de dados) ou null (caso não exista).

2- Crie um ponto de decisão para verificar se o usuário já existe ou não:

Lembrando que você pode reorganizar o fluxo apagando setas e criando outras. Para isso, você deve clicar e arrastar as setas até o card que deseja conectar.

3- Caso o usuário não exista no banco de dados, adicione um card de JSON API para armazenar as informações:

Aqui estamos realizando a chamada POST no endpoint /pessoa  e enviando seu nome e número de WhatsApp para a API.

4- Após armazenar a informação, chamaremos a API de 2 fatores da Zenvia para enviar um código de verificação. Usaremos aqui o Access-Token do painel da API de voz da Zenvia nos cabeçalhos da chamada:

Aqui estamos chamando a API de 2FA da Zenvia e pedindo para que ela gere um código de verificação e o envie por meio de torpedo de voz ao número informado anteriormente.

5- Peça para que o usuário informe o código recebido:

6- Coloque a chamada à API para verificar se o código enviado pelo usuário está realmente correto:

7- Em seguida, coloque um ponto de decisão para verificar se o código é válido ou não:

8- Adicione a última chamada que salvará o agendamento:

9- Adicione uma mensagem de sucesso. Por exemplo, “Seu atendimento foi salvo com sucesso! Aguarde que um dos nossos atendentes entrará em contato!

10- Volte ao primeiro ponto de decisão para criarmos o fluxo em caso de usuário já existente. Basta ligar o caso de sucesso à primeira chamada de verificação que fizemos à API Zenvia:

Pronto! Seu fluxo está completo, chamando 2 APIs diferentes, sendo uma criação nossa e a outra externa, disponibilizada pela Zenvia.

Agora seu cliente poderá agendar um atendimento com facilidade. 

Escrito por

Guilherme Boeira

Leia também

Fique por dentro e confira as nossas dicas sobre o mercado mobile e interação digital.