├── README.md ├── config.js ├── files ├── file-example_PDF_500_kB.pdf ├── file_example_JPG_100kB.jpg ├── file_example_MP3_1MG.mp3 ├── file_example_MP4_480_1_5MG.mp4 ├── sample-vcard.txt └── webhook_example.json ├── index.js ├── package.json └── whapi.d.ts /README.md: -------------------------------------------------------------------------------- 1 | # Free WhatsApp NodeJS Bot (Whapi.Cloud WhatsApp API) 2 | This example of the WhatsApp bot implementation touches in detail on the most frequently used functionality: send message, send file, create group, send message to WhatsApp Group. This will allow you to adapt WhatsApp API and source code to your tasks and needs, or take it as a basis for creating any other integration. 3 | In the source code of the bot you will find the following functionality: 4 | 13 | 14 | You will be able to use our source code in your project, easily modifying and supplementing the script's functionality. Based on the code, you can create your chatbot or any integration. Easily integrate it into existing workflows, continuing to use WhatsApp as usual! 15 | 16 | ### Step-by-step instructions on how to set up and run this chatbot: https://whapi.cloud/setting-up-chatbot-whatsapp-nodejs 17 | We'll talk in detail about how to test the bot on a local, which servers to use, some tips and the main causes of popular failures. 18 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // API endpoint URL 3 | apiUrl: "https://gate.whapi.cloud", 4 | // API token from your channel 5 | token: "YOUR CHANNEL TOKEN", 6 | // The ID of the group to which we will send the message. Use to find out the ID: https://whapi.readme.io/reference/getgroups 7 | group: '120363167596599603@g.us', 8 | // The ID of the product we will send for the example. Create a product in your WhatsApp and find out the product ID: https://whapi.readme.io/reference/getproducts 9 | product: '6559353560856703', 10 | // Bot`s URL (for static file). Webhook Link to your server. At ( {server link}/hook ), when POST is requested, processing occurs 11 | botUrl: "https://yoursite.com/hook", 12 | // Bot's Port (for hook handler). Don't use 443 port. 13 | port: "80" 14 | } 15 | -------------------------------------------------------------------------------- /files/file-example_PDF_500_kB.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whapi-Cloud/nodejs-whatsapp-chatbot/bbb7c697ef2c0b34cf9e81a430b3075a5b2cc9d9/files/file-example_PDF_500_kB.pdf -------------------------------------------------------------------------------- /files/file_example_JPG_100kB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whapi-Cloud/nodejs-whatsapp-chatbot/bbb7c697ef2c0b34cf9e81a430b3075a5b2cc9d9/files/file_example_JPG_100kB.jpg -------------------------------------------------------------------------------- /files/file_example_MP3_1MG.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whapi-Cloud/nodejs-whatsapp-chatbot/bbb7c697ef2c0b34cf9e81a430b3075a5b2cc9d9/files/file_example_MP3_1MG.mp3 -------------------------------------------------------------------------------- /files/file_example_MP4_480_1_5MG.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whapi-Cloud/nodejs-whatsapp-chatbot/bbb7c697ef2c0b34cf9e81a430b3075a5b2cc9d9/files/file_example_MP4_480_1_5MG.mp4 -------------------------------------------------------------------------------- /files/sample-vcard.txt: -------------------------------------------------------------------------------- 1 | BEGIN:VCARD 2 | VERSION:3.0 3 | N:Gump;Forrest;;Mr.; 4 | FN:Forrest Gump 5 | ORG:Bubba Gump Shrimp Co. 6 | TITLE:Shrimp Man 7 | TEL;TYPE=WORK,VOICE:(111) 555-1212 8 | TEL;TYPE=HOME,VOICE:(404) 555-1212 9 | ADR;TYPE=WORK,PREF:;;100 Waters Edge;Baytown;LA;30314;United States of America 10 | LABEL;TYPE=WORK,PREF:100 Waters Edge\nBaytown\, LA 30314\nUnited States of America 11 | ADR;TYPE=HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America 12 | LABEL;TYPE=HOME:42 Plantation St.\nBaytown\, LA 30314\nUnited States of America 13 | EMAIL:forrestgump@example.com 14 | REV:2008-04-24T19:52:43Z 15 | END:VCARD 16 | -------------------------------------------------------------------------------- /files/webhook_example.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whapi-Cloud/nodejs-whatsapp-chatbot/bbb7c697ef2c0b34cf9e81a430b3075a5b2cc9d9/files/webhook_example.json -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const fs = require('fs'); 4 | const fetch = require('node-fetch'); 5 | const FormData = require('form-data'); 6 | const config = require('./config.js'); 7 | 8 | process.on('unhandledRejection', err => { 9 | console.log(err) 10 | }); 11 | 12 | const COMMANDS = { // bot commands 13 | TEXT: 'Simple text message', 14 | IMAGE: 'Send image', 15 | DOCUMENT: 'Send document', 16 | VIDEO: 'Send video', 17 | CONTACT: 'Send contact', 18 | PRODUCT: 'Send product', 19 | GROUP_CREATE: 'Create group', 20 | GROUP_TEXT: 'Simple text message for the group', 21 | GROUPS_IDS: 'Get the id\'s of your three groups' 22 | } 23 | 24 | const FILES = { // file path 25 | IMAGE: './files/file_example_JPG_100kB.jpg', 26 | DOCUMENT: './files/file-example_PDF_500_kB.pdf', 27 | VIDEO: './files/file_example_MP4_480_1_5MG.mp4', 28 | VCARD: './files/sample-vcard.txt' 29 | } 30 | 31 | /** 32 | * Send request to Whapi.Cloud 33 | * @param endpoint - endpoint path 34 | * @param params - request body 35 | * @param method - GET, POST, PATCH, DELETE 36 | * @returns {Promise} 37 | */ 38 | async function sendWhapiRequest(endpoint, params= {}, method = 'POST') { // send request to endpoint with params, with POST by default 39 | let options = { 40 | method: method, 41 | headers: { 42 | Authorization: `Bearer ${config.token}` 43 | }, 44 | }; 45 | if (!params.media) options.headers['Content-Type'] = 'application/json'; // if in params media is null - set json in headers 46 | let url = `${config.apiUrl}/${endpoint}`; 47 | if(params && Object.keys(params).length > 0) { 48 | if(method === 'GET') 49 | url += '?' + new URLSearchParams(params); // if GET method set in params, then params move to query 50 | else 51 | options.body = params?.media ? toFormData(params) : JSON.stringify(params); // if in params media - transform to formData, else - json 52 | } 53 | const response = await fetch(url, options); // send request 54 | let json = await response.json(); 55 | console.log('Whapi response:', JSON.stringify(json, null, 2)); 56 | return json; 57 | } 58 | 59 | /** 60 | * Convert object to FormData 61 | * @param obj 62 | * @returns {FormData} 63 | */ 64 | function toFormData(obj) { 65 | const form = new FormData(); 66 | for (let key in obj) { 67 | form.append(key, obj[key]); 68 | } 69 | return form; 70 | } 71 | 72 | async function setHook() { // request for set hook and recieve messages 73 | if (config.botUrl) { 74 | /** type {import('./whapi').Settings} */ 75 | const settings = { 76 | webhooks: [ 77 | { 78 | url: config.botUrl, 79 | events: [ 80 | // default event for getting messages 81 | {type: "messages", method: "post"} 82 | ], 83 | mode: "method" 84 | } 85 | ] 86 | } 87 | await sendWhapiRequest('settings', settings, 'PATCH'); 88 | } 89 | } 90 | 91 | async function handleNewMessages(req, res){ // handle messages 92 | try { 93 | /** type {import('./whapi').Message[]} */ 94 | const messages = req?.body?.messages; 95 | for (let message of messages) { 96 | if (message.from_me) continue; 97 | /** type {import('./whapi').Sender} */ 98 | const sender = { 99 | to: message.chat_id 100 | } 101 | let endpoint = 'messages/text'; 102 | const command = Object.keys(COMMANDS)[+message.text?.body?.trim() - 1]; 103 | 104 | switch (command) { // depending on the command, perform an action 105 | case 'TEXT': { 106 | sender.body = 'Simple text message'; 107 | break; 108 | } 109 | case 'IMAGE': { 110 | sender.caption = 'Text under the photo.'; 111 | sender.media = fs.createReadStream(FILES.IMAGE); // read file 112 | endpoint = 'messages/image'; 113 | break; 114 | } 115 | case 'DOCUMENT': { 116 | sender.caption = 'Text under the document.'; 117 | sender.media = fs.createReadStream(FILES.DOCUMENT); 118 | endpoint = 'messages/document'; 119 | break; 120 | } 121 | case 'VIDEO': { 122 | sender.caption = 'Text under the video.'; 123 | sender.media = fs.createReadStream(FILES.VIDEO); 124 | endpoint = 'messages/video'; 125 | break; 126 | } 127 | case 'CONTACT': { 128 | sender.name = 'Whapi Test'; 129 | sender.vcard = fs.readFileSync(FILES.VCARD).toString(); 130 | endpoint = 'messages/contact'; 131 | break; 132 | } 133 | case 'PRODUCT': { 134 | /* you can get real product id using endpoint https://whapi.readme.io/reference/getproducts */ 135 | endpoint = `business/products/${config.product}`; 136 | break; 137 | } 138 | case 'GROUP_CREATE': { 139 | /* Warning : you can create group only with contacts from phone contact list */ 140 | const res = await sendWhapiRequest(`groups`, {subject: 'Whapi.Cloud Test', participants: [message.chat_id.split('@')[0]]}); 141 | sender.body = res.group_id ? `Group created. Group id: ${res.group_id}` : 'Error'; 142 | break; 143 | } 144 | case 'GROUP_TEXT': { 145 | /*To get group id, use /groups endpoint */ 146 | sender.to = config.group; 147 | sender.body = 'Simple text message for the group'; 148 | break; 149 | } 150 | case 'GROUPS_IDS': { // get groups 151 | const {groups} = await sendWhapiRequest('groups', {count: 3}, 'GET'); 152 | sender.body = groups && groups.reduce((prevVal, currVal, i) => { 153 | return i === 0 ? `${currVal.id} - ${currVal.name}` : prevVal + ',\n ' + `${currVal.id} - ${currVal.name}`; 154 | }, '') || 'No groups'; 155 | break; 156 | } 157 | default: { // if command not found - set text message with commands 158 | sender.body = 'Hi. Send me a number from the list. Don\'t forget to change the actual data in the code! \n\n' + 159 | Object.values(COMMANDS).map((text, i) => `${i + 1}. ${text}`).join('\n'); 160 | } 161 | } 162 | await sendWhapiRequest(endpoint, sender); // send request 163 | } 164 | res.send('Ok'); 165 | } catch (e) { 166 | res.send(e.message); 167 | } 168 | } 169 | 170 | // Create a new instance of express 171 | const app = express(); 172 | app.use(bodyParser.json()); 173 | 174 | app.get('/', function (req, res) { 175 | res.send('Bot is running'); 176 | }); 177 | 178 | app.post('/hook/messages', handleNewMessages); // route for get messages 179 | 180 | setHook().then(() => { 181 | const port = config.port || (config.botUrl.indexOf('https:') === 0 ? 443 : 80) // if port not set - set port 443 (if https) or 80 (if http) 182 | app.listen(port, function () { 183 | console.log(`Listening on port ${port}...`); 184 | }); 185 | }); 186 | 187 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "whatsapp-bot", 3 | "version": "1.0.0", 4 | "description": "Simple bot for whapi.cloud", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node index.js" 8 | }, 9 | "author": "A.K.", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.19.0", 13 | "express": "^4.17.1", 14 | "form-data": "^4.0.0", 15 | "node-fetch": "^2.6.0" 16 | } 17 | } 18 | --------------------------------------------------------------------------------