Integração com WhatsAPP através de API – NETiZAP

Introdução

O WhatsApp tornou-se o aplicativo de mensagens instantâneas para Smartphones mais usado no mundo, atingindo a marca de 1 bilhão de usuários em fevereiro de 2016. Em janeiro de 2018, surgiu a versão “Business” do aplicativo, e em agosto do mesmo ano foi disponibilizada uma integração via API WEB, viabilizando integrações automáticas por sistemas, como atendimentos automatizados, robôs de chat e afins. Durante as buscas de onde/como enviar mensagens para WhatsApp usando esta tecnologia, encontrei uma API de integração via HTTP / WebRequests, chamada NETiZAP. Nesse post vamos ver o que é e como usar essa API, usando uma classe de encapsulamento em AdvPL 😀

NETiZAP API

Trata-se de uma API comercial de integração com o WhatsApp que recebe requisições de integração via HTTP (GET/POST), o que a torna muito simples de ser consumida. Basicamente a API disponibiliza até o momento 9 operações :

  • message_send: Envio de mensagem
  • question_send: Envio de mensagem com pergunta
  • file_send: Envio de mensagem com arquivo anexo
  • message_search: Consulta de status de mensagem enviada
  • question_search: Consulta de status de resposta de uma pergunta
  • group_search: Consulta grupos de envio de mensagens registrados para a linha
  • broadcast_search: Consulta listas de broadcast registrados para a linha
  • check_credits: Consulta o status / créditos para o plano de mensagens contratado
  • requests_start: Consulta o consumo e requisições feitas pela API

A API trabalha com strings em UTF-8, cada requisição possui parâmetros enviados pela URL e/ou por POST de formulário, a string retornada para cada requisição está em formato JSON.

O provedor do serviço fornece uma chave de acesso para testes, atrelada a uma linha de origem. Com ela você pode testar o serviço e enviar por exemplo uma mensagem, arquivo ou pergunta para o seu celular. Para uso em produção e implementação de rotinas, você deve entrar em contato com o provedor da NETiZAP e adquirir um plano pago — com uma linha personalizada atrelada a uma chave de acesso exclusiva — ou solicitar uma chave personalizada para testes. Independente do plano adquirido, é proibido usar a API para fazer SPAM, e as regras de uso são supervisionadas e apicadas pela WhatsApp.

Para utilizar comercialmente a API NETiZAP, entre em contato com Thiago — WhatsApp (27) 998022075.

Classe AdvPL NETiZAP

Disponível no GITHUB (https://github.com/siga0984/NETiZAP) — sob licenciamento de uso livre e irrestrito — a classe AdvPL NETIZAP encapsula os tratamentos básicos de requisição para cada um dos serviços disponíveis. O fonte não depende do projeto ZLIB, pode ser baixado e compilado diretamente em qualquer ambiente do Protheus Server com build igual ou posterior a 7.00.131227 — independente da versão do ERP em uso — Protheus 11, Protheus 12 NG, Protheus 12 LG).

A classe disponibiliza cada operação em um método, que encapsula o envio e retorno da requisição para o provedor da API. Os métodos em si não recebem parâmetros diretamente, você deve atribuir os valores nas propriedades necessárias da instância em uso da classe antes de chamar o método.

Ao criar a instância da classe, você deve fornecer a linha registrada para origem das mensagens, e a respectiva chave de acesso, e opcionalmente a porta HTTP do provedor de serviços. O provedor do serviço está publicado no host “api.meuaplicativo.vip”, e para fins de demonstração, os dados abaixo podem ser utilizados:

Linha .............. 5527981049976
Chave de Acesso .... Voz5dWkr5EEhBAbYuwJ2
Porta HTTP ......... 13005

Antes de mais nada, vamos ao exemplo de envio de uma mensagem usando a classe:

USER Function MsgSend()
Local oNetIZap 
Local cResponse

// Cria o objeto client usando a chave de demostração
oNetIZap := NETIZAP():New("5527981049976",'Voz5dWkr5EEhBAbYuwJ2',13005)

// Define as propriedades minimas para envio de mensagem 
// *** Número do Celular (WhatsApp) no formato internacional, apenas nímeros
// por exemplo para um telefone celular de São Paulo, 
// utilize "5511" seguido pelo número da linha a enviar a mensagem
oNetIZap:SetDestiny("5511xxxxxxxxx")

// Informa o texto da mensagem 
// 
oNetIZap:SetText(EncodeUTF8("*Olá!*\nEsta é uma mensagem de _teste_ enviada pelo Protheus."))

// Realiza o envio da mensagem 

If oNetIZap:MessageSend()

  // Pega o JSON de retorno da requisiçao 
  // Cada mensagem enviada retorna um identificador de protocolo 
  // no formato "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".   
  cResponse := oNetIZap:GetResponse()

  // Mostra na inteface 
  MsgInfo(cResponse,"MessageSend() - Retorno da Requisição")

Else

  // Em caso de falha no envio, recupera o erro 
  MSgStop(oNetIZap:GetLastError(),'MessageSend() - Falha no envio da requisição')

Endif

Return

Em caso de sucesso no envio da mensagem, devemos obter o seguinte resultado:

NETiZap - MEssageSend

O número de protocolo retornado é usado para confirmarmos se a mensagem foi recebida e lida pelo destinatário, usando o método MessageSearch(), vide exemplo abaixo:

USER Function MsgSearch()

Local oNetIZap 
Local cResponse

// Cria o objeto client usando uma chave de demmostração
oNetIZap := NETIZAP():New("5527981049976",'Voz5dWkr5EEhBAbYuwJ2')

// Informa o protococolo da mensagem a ser pesquisada
oNetIZap:SetProtocol("E8891831-2FF4-43B2-8388-2C6D01C7D0A6")

If oNetIZap:MessageSearch()

  cResponse := oNetIZap:GetResponse()
  MsgInfo(cResponse,"MessageSearch() - Retorno da Requisição")

Else

  MsgStop(oNetIZap:GetLastError(),'MessageSearch() - Falha no envio da requisição')

Endif

Return

Em caso de sucesso, devemos receber o seguinte retorno:

NETiZap - MEssageSearch

Agora, vamos ver com mais detalhes cada um dos métodos disponíveis e como cada um deles funciona.

Método MessageSend()

Exige que seja informada a linha de destino da mensagem — usando o método SetDestiny() — usando uma string contendo apenas números: Codigo do País, seguido do DDD e do número de destino, e uma mensagem de texto — usando a codificação/encoding UTF-8 — contendo o texto a ser enviado. É uma boa prática não enviar mensagens maiores que 512 Bytes — para conteúdos maiores envie um arquivo anexo 😀

Para fins de rastreabilidade e controle, opcionalmente podemos informar um valor chamado de “referência” — usando o método SetReference() —  de até 60 caracteres, que será guardado pelo provedor do serviço junto da mensagem. Quando você consultar a mensagem usando o protocolo fornecido no envio, este número também é retornado — vide exemplo acima,  como não foi informado um número de referência na mensagem enviada, o valor de “reference” retornado na consulta da mensagem veio em branco.

É possível o envio para grupos de mensagens e listas de broadcast registradas no provedor para a linha contratada. Para isso, usamos os métodos GroupSearch() e BroadcastSearch() respectivamente, e informamos o identificador do grupo ou lista “id” ao invés do número de telefone do destinatário — também usando o método SetDestiny()

Método FileSend()

Para envio de uma mensagem com arquivo anexo, devemos preencher todas as propriedades obrigatórias para envio de uma mensagem — destinatário e texto da mensagem — e informar através do método SetFile() o tipo de arquivo a ser enviado — PDF, JPG, PNG, etc — , o nome do arquivo que deve aparecer na mensagem, e o conteúdo binário do arquivo, codificado em BASE64. Por exemplo, para enviar o arquivo chamado “\filetosend.pdf” que está salvo em disco no seu ambiente a partir do rootpath para um destinatário, que deve receber esse arquivo com o nome ‘meucomprovante.pdf’, usamos por exemplo:

oNetIZap:SetFile("meucomprovante.pdf","PDF",Encode64(MemoRead('\filetosend.pdf')))

Repare que usamos a função MemoRead() para ler o arquivo no disco e retornar seu conteúdo. Se esquecermos de ler o arquivo e colocarmos como parâmetro apenas o nome do arquivo, o destinatário vai receber um arquivo com a string “\filetosend.pdf” como conteúdo 😛

Método QuestionSend()

Podemos enviar uma mensagem que deve ser respondida pelo destinatário. Uma mensagem com pergunta deve conter uma informação chamada  “Question” para envio, onde informamos as respostas esperadas da pergunta. Neste caso a API envia a mensagem ao destinatário, e entende que a próxima mensagem que o destinatário enviar será interpretada como a resposta da pergunta enviada. O texto enviado como resposta sempre será recebido pela API, mesmo que não seja uma das alternativas informadas na pergunta. O método retorna um protocolo de mensagem, mas para saber se ou o que foi respondido para uma pergunta, devemos usar o método QuestionSearch(). Se usarmos o método MessageSearch() com um protocolo de uma pergunta enviada pelo QuestionSend(), a API retorna um erro dizendo que não encontrou a mensagem.

Método MessageSearch()

Usando um número de protocolo de mensagem enviada — obtido no retorno do método MessageSend() ou FileSend() — podemos verificar se a mensagem foi enviada com sucesso ao destinatário, como vimos no exemplo mais acima. É necessário apenas informar o número de protocolo da mensagem, retornado pelo envio de mensagens feitos com MessageSend() e/ou FileSend(). Segue abaixo exemplo de retorno:

{
 "reference":"",
 "sent":"true",
 "sent_datehour":"2019-12-03T13:30:46",
 "destiny":"5511*********",
 "error":"false"
}

Método QuestionSearch()

Uma mensagem com pergunta enviada pelo método QuestionSend() pode ser consultada usando o método QuestionSearch(). Veja abaixo um exemplo de retorno de uma pergunta respondida com uma das alternativas informadas na pergunta:

{"reference":"",
 "sent":"true",
 "sent_datehour":"2019-12-03T22:59:42",
 "destiny":"5511*********",
 "error":"false",
 "question_answer":"true",
 "question_answer_correct":"true",
 "question_response":"2",
 "question_expired":"false"}

Método GroupSearch()

Este método não exige parâmetros adicionais, e retorna um JSON contendo os grupos de mensagens associados ao plano / conta atuais, vide exemplo de retorno abaixo:

 {"root":
  [
   {"id":"5527998022075-1565662333@g.us",
    "descricao":"My Group Example"},
   {"id":"5527988543306-1574680080@g.us",
    "descricao":"Teste API"}
  ]
}

O “id” da lista retornada pode ser usado como destinatário — SetDDestiny() — de uma mensagem, arquivo ou pergunta.

Método BroadcastSearch()

Este método não exige parâmetros adicionais, e retorna um JSON contendo os grupos de mensagens associados ao plano / conta atuais, vide exemplo de retorno abaixo:

{"root":
  [
    {"id":"1573267020@broadcast","descricao":"My Broadcast Example"}
  ]
}

O “id” do grupo retornado pode ser usado como destinatário — SetDDestiny() — de uma mensagem, arquivo ou pergunta.

Método RequestsStart()

Este método não exige parâmetros, e retorna um JSON com um resumo das mensagens enviadas pelo plano atual, agrupando por destinatário. Vide abaixo um exemplo de retorno:

{
  "root": [
    {
      "phone": "55119********",
      "message_datehour_first": "2019-12-04T00:27:22",
      "message_datehour_last": "2019-12-04T00:27:22",
      "messages": [
        {
          "id": "8651",
          "datehour": "2019-12-04T00:27:22",
          "message": "1"
        }
      ],
       "messages_count": 1
     }
  ]
}

Conclusão

Se usa protocolo sobre TCP, recebe parâmetros e tem retorno, dá pra usar em AdvPL 😛 Aguardem novidades no próximo post sobre esse assunto, estou montando uma aplicação de exemplo em AdvPL com interface — SmartClient — para consumir essas APIs de modo interativo 😀

Agradeço novamente a audiência e lhes desejo TERABYTES DE SUCESSO 😀 

Referências

A API foi escrita com base na documentação disponível no link PostMan – NETiZAP Messages API, bem como nos exemplos de conexão publicados no post “SQL Server – Como enviar mensagens para contatos, grupos e listas de transmissão do Whatsapp via API“, do Blog do DBA Dirceu Resende, que inclusive tem mais informações, e um link de Download de uma aplicação de exemplo fornecida pelo provedor 😀

 

6 comentários sobre “Integração com WhatsAPP através de API – NETiZAP

  1. Muito bom Julio. Sempre surpreendendo.
    Vc teria um exemplo utilizando o QuestionSend(). Nos meus testes, sempre retorna erro de “expressao contem caracteres incorretos”

    Valeu meu amigo!

    Curtido por 1 pessoa

  2. Muito bom!
    Estamos pensando seriamente em aplicar aqui na empresa, porem quão confiável é de se usar comercialmente? Não digo a sua integração em ADVPL, mas a NETZAP mesmo, afinal é uma comunicação não oficial, será que não pode render alguma punição por parte do Zuckenberg?

    Curtido por 1 pessoa

    • Fala Patrick, beleza ? Entre em contato com o Thiago — WhatsApp (27) 998022075 — ele pode te dar mais referências de outros clientes que usam o serviço. Quanto as regras de uso, só sei que não pode ser usado para fazer “Spam”. O serviço prestado tem regras controladas pelo proprio Facebook, liga pro Thiago e tira as suas dúvidas com ele 😀

      Curtir

      • Eu conversei com ele! Só queria ver se outros DEVs tinham alguma experiência com o serviço. Mas ta ótimo, Muito boa integração, mal posso esperar por mais posts sobre, pois tenho ainda algumas duvidas de como funcionaria para manter o serviço rodando 24Hrs, não tenho muita experiência com esse tipo de aplicação.

        Curtido por 2 pessoas

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s