Como achei caro o valor da API, encontrei essa opção para envio de Whatsapp grátis e resolvi compartilhar!
Link para demonstração/instalação https://zapdasgalaxias.com.br/wwebjs-md/
Coloquei a API em uma VPS AWS free, estou rodando 5 instancias, apenas modificando a porta no arquivo app.js. Também funciona local.
É possível a capturar o QR CODE pelo navegador.
Como utilizo:
Ao fechar o atendimento o cliente recebe uma mensagem de agradecimento.
Botão de envio na agenda, informando a marcação ou desmarcação. (envia para cliente e profissional)
Método PHP (do atendimento)
//--------------------------------------
//ENVIO DE MENSAGEM WHATSAPP
// CLIENTE
sc_lookup(cs,“SELECT nome, fone1, sexo
FROM clientes
WHERE idcliente = {cliente_id}”);
$_cliente_nome = {cs[0][0]};
$_cliente_fone = {cs[0][1]};
$_cliente_sexo = {cs[0][2]};
$_check_fone = substr($_cliente_fone,4,1);
//seleciona url
sc_lookup(rs,“SELECT whatsapp_url
FROM empresas
WHERE idempresa = [vg_empresa_id]”);
// verifica whatsapp_mensagens
sc_lookup(ws,“SELECT idwhatsappmensagem, saudacao, mensagem_mulher, mensagem_homem, assinatura
FROM whatsapp_mensagens
WHERE tipo = ‘A’
AND ativo = ‘S’”);
if( $_check_fone == 9 and !empty({rs[0][0]}) and isset({ws[0][0]}) ){
$site = {rs[0][0]};
$primeiroNome = explode(" ", $_cliente_nome);
$cliente = ucfirst(strtolower($primeiroNome[0]));
if(substr($_cliente_fone,0,4) > 5530){
$_fone = substr($_cliente_fone,0,4).substr($_cliente_fone,5,12);
}else{
$_fone = $_cliente_fone;
}
//seta variáveis de saudação, mensagem e assinatura
$_saudacao = {ws[0][1]};
if( $_cliente_sexo == 'F'){
$_msg = {ws[0][2]};
}else{
$_msg = {ws[0][3]};
}
$_assinatura = {ws[0][4]};
$_mensagem = $_saudacao.' '.$cliente.' '.$_msg.' '.$_assinatura;
// url
$url = $site.'send-message';
$data = array('number' => $_fone, 'message' => $_mensagem);
//monta disparo da API
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
//dispara a mensagem da API
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
}
// Botão PHP (agenda)
//--------------------------------------
//ENVIO DE MENSAGEM WHATSAPP
$_check_fone = substr({fone},4,1);
//seleciona url
sc_lookup(rs,“SELECT whatsapp_url
FROM empresas
WHERE idempresa = [vg_empresa_id]”);
// verifica whatsapp_mensagens
sc_lookup(ws,“SELECT idwhatsappmensagem, saudacao, mensagem_mulher, mensagem_homem, assinatura
FROM whatsapp_mensagens
WHERE tipo = ‘G’
AND ativo = ‘S’”);
if( $_check_fone == 9 and !empty({rs[0][0]}) and isset({ws[0][0]}) ){
$site = {rs[0][0]};
$primeiroNome = explode(" ", {nome});
$cliente = ucfirst(strtolower($primeiroNome[0]));
if(substr({fone},0,4) > 5530){
$_fone = substr({fone},0,4).substr({fone},5,12);
}else{
$_fone = {fone};
}
//seta variáveis de saudação, mensagem e assinatura
$_saudacao = {ws[0][1]};
$_assinatura = {ws[0][4]};
sc_lookup(prof,"SELECT nome, sexo, fone1
FROM profissionais
WHERE idprofissional = {profissional_id}");
sc_lookup(serv,"SELECT descricao
FROM agendas_servicos
WHERE idagendaservico = {servico_id}");
$data_ = sc_date_conv({data_inicial},"yyyymmdd","dd/mm/yyyy");
$time_ = explode(":", {hora_inicial});
$hora_ = date('H:i', mktime($time_[0],$time_[1]));
if( {prof[0][1]} == 'F'){
$_msg = $cliente."! Seu serviço de ".{serv[0][0]}." foi agendado para o dia ".$data_." às ".$hora_." horas, com a profissional ".{prof[0][0]}." ";
}elseif( {prof[0][1]} == 'M'){
$_msg = $cliente."! Seu serviço de ".{serv[0][0]}." foi agendado para o dia ".$data_." às ".$hora_." horas, com o profissional ".{prof[0][0]}." ";
}
$_mensagem = $_saudacao.' '.$_msg.' '.$_assinatura;
// url
$url = $site.'send-message';
$data = array('number' => $_fone, 'message' => $_mensagem);
//monta disparo da API
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
//dispara a mensagem da API
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
// PROFISSIONAL
if ( isset({prof[0][2]}) ){
$prof_fone = substr({prof[0][2]},0,4).substr({prof[0][2]},5,12);
if({sexo} == 'F'){
$_msg = {prof[0][0]}."! A cliente ".$cliente.", agendou o serviço de ".{serv[0][0]}." para o dia ".$data_." às ".$hora_." horas ";
}elseif({sexo} == 'M'){
$_msg = {prof[0][0]}."! O cliente ".$cliente.", agendou o serviço de ".{serv[0][0]}." para o dia ".$data_." às ".$hora_." horas ";
}
$_mensagem = $_saudacao.' '.$_msg.' '.$_assinatura;
// url
$url = $site.'send-message';
$data = array('number' => $prof_fone, 'message' => $_mensagem);
//monta disparo da API
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
//dispara a mensagem da API
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
}
}
sc_commit_trans ();
sc_exit(ref);
//--------------------------------------------------------------------
APP.JS - adaptado
//------------
const { Client, List, Buttons, MessageMedia } = require(‘whatsapp-web.js’);
const express = require(‘express’);
const { body, validationResult } = require(‘express-validator’);
const socketIO = require(‘socket.io’);
const qrcode = require(‘qrcode’);
const http = require(‘http’);
const fs = require(‘fs’);
const { phoneNumberFormatter } = require(’./helpers/formatter’);
const fileUpload = require(‘express-fileupload’);
const axios = require(‘axios’);
const mime = require(‘mime-types’);
const fsPromises = require(“fs/promises”);
const port = process.env.PORT || 8000;
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
app.use(express.json());
app.use(express.urlencoded({
extended: true
}));
app.use(fileUpload({
debug: true
}));
const SESSION_FILE_PATH = ‘./whatsapp-session.json’;
let sessionCfg;
if (fs.existsSync(SESSION_FILE_PATH)) {
sessionCfg = require(SESSION_FILE_PATH);
}
app.get(’/’, (req, res) => {
res.sendFile(‘index.html’, {
root: __dirname
});
});
const client = new Client({ puppeteer: { headless: false }, clientId: ‘bot’ });
client.initialize();
/*
client.on(‘message’, msg => {
if (msg.body !== null && msg.body.includes(“Oi”)) {
msg.reply(“Oi!”);
}
});
*/
// Socket IO
io.on(‘connection’, function(socket) {
socket.emit(‘message’, ‘Verificando conexão…’);
client.on(‘qr’, (qr) => {
console.log(‘QR RECEIVED’, qr);
qrcode.toDataURL(qr, (err, url) => {
socket.emit(‘qr’, url);
socket.emit(‘message’, ‘QR code recebido, aguardando leitura!’);
});
});
client.on(‘ready’, () => {
socket.emit(‘ready’, ‘Whatsapp is ready!’);
//socket.emit(‘message’, ‘Whatsapp está conectado!’);
});
client.on(‘authenticated’, (session) => {
socket.emit(‘authenticated’, ‘Whatsapp is authenticated!’);
socket.emit(‘message’, ‘Whatsapp está autenticado!’);
console.log(‘AUTHENTICATED’, session);
sessionCfg = session;
/*
fs.writeFile(SESSION_FILE_PATH, JSON.stringify(session), function(err) {
if (err) {
console.error(err);
}
});
*/
});
client.on(‘auth_failure’, function(session) {
socket.emit(‘message’, 'Falha na autenticação, recarregue a página ');
});
client.on(‘disconnected’, (reason) => {
socket.emit(‘message’, ‘Whatsapp está desconectado!’);
/*
fs.unlinkSync(SESSION_FILE_PATH, function(err) {
if(err) return console.log(err);
console.log(‘Session file deleted!’);
});
client.destroy();
client.initialize();
*/
});
});
const checkRegisteredNumber = async function(number) {
const isRegistered = await client.isRegisteredUser(number);
return isRegistered;
}
// Send message
app.post(’/send-message’, [
body(‘number’).notEmpty(),
body(‘message’).notEmpty(),
], async (req, res) => {
const errors = validationResult(req).formatWith(({
msg
}) => {
return msg;
});
if (!errors.isEmpty()) {
return res.status(422).json({
status: false,
message: errors.mapped()
});
}
const number = phoneNumberFormatter(req.body.number);
const message = req.body.message;
const isRegisteredNumber = await checkRegisteredNumber(number);
if (!isRegisteredNumber) {
return res.status(422).json({
status: false,
message: ‘The number is not registered’
});
}
client.sendMessage(number, message).then(response => {
res.status(200).json({
status: true,
response: response
});
}).catch(err => {
res.status(500).json({
status: false,
response: err
});
});
});
// Send media
app.post(’/send-media’, async (req, res) => {
const number = phoneNumberFormatter(req.body.number);
const caption = req.body.caption;
const url = req.body.url;
// const media = MessageMedia.fromFilePath(’./image-example.png’);
// const file = req.files.file;
// const media = new MessageMedia(file.mimetype, file.data.toString(‘base64’), file.name);
let mimetype;
const attachment = await axios.get(url, {
responseType: ‘arraybuffer’
}).then(response => {
mimetype = response.headers[‘content-type’];
return response.data.toString(‘base64’);
});
const media = new MessageMedia(mimetype, attachment, ‘Media’);
const isRegisteredNumber = await checkRegisteredNumber(number);
if (!isRegisteredNumber) {
return res.status(422).json({
status: false,
message: ‘The number is not registered’
});
}
client.sendMessage(number, media, {
caption: caption
}).then(response => {
res.status(200).json({
status: true,
response: response
});
}).catch(err => {
res.status(500).json({
status: false,
response: err
});
});
});
const findGroupByName = async function(name) {
const group = await client.getChats().then(chats => {
return chats.find(chat =>
chat.isGroup && chat.name.toLowerCase() == name.toLowerCase()
);
});
return group;
}
server.listen(port, function() {
console.log('App running on *: ’ + port);
});