├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── app.js ├── app.json ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Amirul Zharfan Zalid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node app.js 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Whatsapp Direct Messaging API 2 | This API allows user to create a link to their whatsapp account without the needs to save the phone number. Using it on the desktop will start a conversation using Whatsapp Web while on mobile Whatsapp will automatically open and start a conversation. 3 | 4 | It's more like 'Click to Whatsapp' thingy or maybe 'Surf to Whatsapp'. Have fun! 5 | 6 | > You can also use the official one below. 7 | 8 | ## Features 9 | 1. You can use your own domain. 10 | 2. No more saving phone number just to start a conversation. 11 | 3. Directly open whatsapp application using web for desktop and app for mobile (the official api doesn't do this, will ask the user to click send button). 12 | 13 | ## Installation 14 | 15 | ### Local 16 | ```bash 17 | $ git clone https://github.com/amizz/Whatsapp-Direct-Messaging-API.git 18 | $ yarn install 19 | $ yarn start 20 | ``` 21 | > Use NPM if Yarn is not available on your system. Replace yarn to npm when executing the command. 22 | 23 | ### Heroku 24 | 25 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 26 | 27 | ## API 28 | 29 | ``` 30 | http:/// 31 | ``` 32 | > Directly open whatsapp to respective phone number as long as the phone number is registered on whatsapp. 33 | > No message included. 34 | 35 | 36 | ``` 37 | http://// 38 | ``` 39 | > Directly open whatsapp to respective phone number. Message is automatically included. 40 | 41 | 42 | ``` 43 | http:///whatsapp 44 | ``` 45 | > Directly open whatsapp and start conversation using predefined phone number. Go to app.js line 72 to change the phone number. 46 | 47 | 48 | **Example** 49 | ``` 50 | http://localhost:5000/60123456789 51 | http://localhost:5000/60123456789/Hello! 52 | ``` 53 | 54 | > Phone number must include the country code without '+' symbol. 55 | 56 | ## Compatibility 57 | | OS | Browser | Status | 58 | | ---------------- | ---------------- | ---------- | 59 | | Windows 10 | Google Chrome | Success | 60 | | Android 4.4.4 | Google Chrome | Success | 61 | 62 | ## Specification 63 | - Node.js - v4.8.0+ 64 | - Express - v4.15.2 65 | 66 | > This project was tested using Node.js v6.10.0 67 | 68 | ## Official Whatsapp 'Click to Chat' API 69 | ``` 70 | api.whatsapp.com/send?phone=&text= 71 | ``` 72 | 73 | ## License 74 | Whatsapp Direct Messaging API is licensed under The MIT License. Please refer to the license file for more information. -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Whatsapp Direct Messaging API 3 | * Author: Amirul Zharfan Zalid 4 | * Web: amirulzharfan.com 5 | */ 6 | 7 | /***************************************/ 8 | /******* Dependencies *******/ 9 | /***************************************/ 10 | var express = require('express'); 11 | var app = express(); 12 | var useragent = require('express-useragent'); 13 | const port = process.env.PORT || 5000; 14 | 15 | /***************************************/ 16 | /******* Router *******/ 17 | /***************************************/ 18 | 19 | /* 20 | * http:// 21 | * Desciption: Main page 22 | */ 23 | app.get('/', (req, res) => { 24 | var data = { 25 | status: "success", 26 | message: "Hello to whatsapp direct message api. Developed by Amirul Zharfan Zalid - Github@amizz" 27 | } 28 | res.status(200).json(data); 29 | }) 30 | 31 | /* 32 | * http:///:phonenum 33 | * Desciption: Redirect url to respective whatsapp api interface without message text 34 | */ 35 | app.get('/:phonenum', (req, res) => { 36 | var source = req.header('user-agent'); 37 | var ua = useragent.parse(source); 38 | 39 | if (ua.isDesktop) { 40 | res.status(308).redirect(`https://web.whatsapp.com/send?phone=+${req.params.phonenum}`); 41 | } else if (ua.isMobile) { 42 | res.status(308).redirect(`whatsapp://send?phone=+${req.params.phonenum}`); 43 | } else { 44 | res.status(400).json({status: "error"}); 45 | } 46 | }) 47 | 48 | /* 49 | * http:///:phonenum/:message 50 | * Desciption: Redirect url to respective whatsapp api interface with message text 51 | */ 52 | app.get('/:phonenum/:message', (req, res) => { 53 | var source = req.header('user-agent'); 54 | var ua = useragent.parse(source); 55 | 56 | if (ua.isDesktop) { 57 | res.status(308).redirect(`https://web.whatsapp.com/send?phone=+${req.params.phonenum}&text=${req.params.message}`); 58 | } else if (ua.isMobile) { 59 | res.status(308).redirect(`whatsapp://send?phone=+${req.params.phonenum}&text=${req.params.message}`); 60 | } else { 61 | res.status(400).json({status: "error"}); 62 | } 63 | }) 64 | 65 | /* 66 | * http:///whatsapp 67 | * Desciption: Redirect url to respective whatsapp api interface using predefined phone number 68 | */ 69 | app.get('/whatsapp', (req, res) => { 70 | var source = req.header('user-agent'); 71 | var ua = useragent.parse(source); 72 | var phonenum = '0123456789'; 73 | 74 | if (ua.isDesktop) { 75 | res.status(308).redirect(`https://web.whatsapp.com/send?phone=+${phonenum}`); 76 | } else if (ua.isMobile) { 77 | res.status(308).redirect(`whatsapp://send?phone=+${phonenum}`); 78 | } else { 79 | res.status(400).json({status: "error"}); 80 | } 81 | }) 82 | 83 | // Start server at 84 | app.listen(port, (err) => { 85 | console.log(`Available at http://localhost:${port}`); 86 | if (err) { 87 | console.log(err); 88 | } 89 | }) -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "whatsapp-direct-messaging-api", 3 | "description": "A simple whatsapp direct messaging api", 4 | "repository": "https://github.com/amizz/Whatsapp-Direct-Messaging-API", 5 | "keywords": ["node", "express", "static", "whatsapp", "api"] 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "whatsapp-direct-messaging-api", 3 | "version": "0.2.0", 4 | "author": { 5 | "name": "Amirul Zharfan Zalid", 6 | "email": "amirulzharfan96@gmail.com", 7 | "url": "https://www.amirulzharfan.com" 8 | }, 9 | "main": "app.js", 10 | "license": "MIT", 11 | "scripts": { 12 | "start": "node app.js" 13 | }, 14 | "dependencies": { 15 | "express": "^4.15.2", 16 | "express-useragent": "^1.0.7" 17 | }, 18 | "devDependencies": {} 19 | } 20 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.3: 6 | version "1.3.3" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" 8 | dependencies: 9 | mime-types "~2.1.11" 10 | negotiator "0.6.1" 11 | 12 | array-flatten@1.1.1: 13 | version "1.1.1" 14 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 15 | 16 | content-disposition@0.5.2: 17 | version "0.5.2" 18 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 19 | 20 | content-type@~1.0.2: 21 | version "1.0.2" 22 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" 23 | 24 | cookie-signature@1.0.6: 25 | version "1.0.6" 26 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 27 | 28 | cookie@0.3.1: 29 | version "0.3.1" 30 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 31 | 32 | debug@2.6.1: 33 | version "2.6.1" 34 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" 35 | dependencies: 36 | ms "0.7.2" 37 | 38 | depd@1.1.0, depd@~1.1.0: 39 | version "1.1.0" 40 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" 41 | 42 | destroy@~1.0.4: 43 | version "1.0.4" 44 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 45 | 46 | ee-first@1.1.1: 47 | version "1.1.1" 48 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 49 | 50 | encodeurl@~1.0.1: 51 | version "1.0.1" 52 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" 53 | 54 | escape-html@~1.0.3: 55 | version "1.0.3" 56 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 57 | 58 | etag@~1.8.0: 59 | version "1.8.0" 60 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" 61 | 62 | express-useragent@^1.0.7: 63 | version "1.0.7" 64 | resolved "https://registry.yarnpkg.com/express-useragent/-/express-useragent-1.0.7.tgz#153de647e5a5d05c4ec1b4172794a46bc0d07991" 65 | 66 | express@^4.15.2: 67 | version "4.15.2" 68 | resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" 69 | dependencies: 70 | accepts "~1.3.3" 71 | array-flatten "1.1.1" 72 | content-disposition "0.5.2" 73 | content-type "~1.0.2" 74 | cookie "0.3.1" 75 | cookie-signature "1.0.6" 76 | debug "2.6.1" 77 | depd "~1.1.0" 78 | encodeurl "~1.0.1" 79 | escape-html "~1.0.3" 80 | etag "~1.8.0" 81 | finalhandler "~1.0.0" 82 | fresh "0.5.0" 83 | merge-descriptors "1.0.1" 84 | methods "~1.1.2" 85 | on-finished "~2.3.0" 86 | parseurl "~1.3.1" 87 | path-to-regexp "0.1.7" 88 | proxy-addr "~1.1.3" 89 | qs "6.4.0" 90 | range-parser "~1.2.0" 91 | send "0.15.1" 92 | serve-static "1.12.1" 93 | setprototypeof "1.0.3" 94 | statuses "~1.3.1" 95 | type-is "~1.6.14" 96 | utils-merge "1.0.0" 97 | vary "~1.1.0" 98 | 99 | finalhandler@~1.0.0: 100 | version "1.0.0" 101 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.0.tgz#b5691c2c0912092f18ac23e9416bde5cd7dc6755" 102 | dependencies: 103 | debug "2.6.1" 104 | encodeurl "~1.0.1" 105 | escape-html "~1.0.3" 106 | on-finished "~2.3.0" 107 | parseurl "~1.3.1" 108 | statuses "~1.3.1" 109 | unpipe "~1.0.0" 110 | 111 | forwarded@~0.1.0: 112 | version "0.1.0" 113 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" 114 | 115 | fresh@0.5.0: 116 | version "0.5.0" 117 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" 118 | 119 | http-errors@~1.6.1: 120 | version "1.6.1" 121 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" 122 | dependencies: 123 | depd "1.1.0" 124 | inherits "2.0.3" 125 | setprototypeof "1.0.3" 126 | statuses ">= 1.3.1 < 2" 127 | 128 | inherits@2.0.3: 129 | version "2.0.3" 130 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 131 | 132 | ipaddr.js@1.2.0: 133 | version "1.2.0" 134 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" 135 | 136 | media-typer@0.3.0: 137 | version "0.3.0" 138 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 139 | 140 | merge-descriptors@1.0.1: 141 | version "1.0.1" 142 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 143 | 144 | methods@~1.1.2: 145 | version "1.1.2" 146 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 147 | 148 | mime-db@~1.26.0: 149 | version "1.26.0" 150 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" 151 | 152 | mime-types@~2.1.11, mime-types@~2.1.13: 153 | version "2.1.14" 154 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" 155 | dependencies: 156 | mime-db "~1.26.0" 157 | 158 | mime@1.3.4: 159 | version "1.3.4" 160 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 161 | 162 | ms@0.7.2: 163 | version "0.7.2" 164 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" 165 | 166 | negotiator@0.6.1: 167 | version "0.6.1" 168 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 169 | 170 | on-finished@~2.3.0: 171 | version "2.3.0" 172 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 173 | dependencies: 174 | ee-first "1.1.1" 175 | 176 | parseurl@~1.3.1: 177 | version "1.3.1" 178 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" 179 | 180 | path-to-regexp@0.1.7: 181 | version "0.1.7" 182 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 183 | 184 | proxy-addr@~1.1.3: 185 | version "1.1.3" 186 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" 187 | dependencies: 188 | forwarded "~0.1.0" 189 | ipaddr.js "1.2.0" 190 | 191 | qs@6.4.0: 192 | version "6.4.0" 193 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 194 | 195 | range-parser@~1.2.0: 196 | version "1.2.0" 197 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 198 | 199 | send@0.15.1: 200 | version "0.15.1" 201 | resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" 202 | dependencies: 203 | debug "2.6.1" 204 | depd "~1.1.0" 205 | destroy "~1.0.4" 206 | encodeurl "~1.0.1" 207 | escape-html "~1.0.3" 208 | etag "~1.8.0" 209 | fresh "0.5.0" 210 | http-errors "~1.6.1" 211 | mime "1.3.4" 212 | ms "0.7.2" 213 | on-finished "~2.3.0" 214 | range-parser "~1.2.0" 215 | statuses "~1.3.1" 216 | 217 | serve-static@1.12.1: 218 | version "1.12.1" 219 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" 220 | dependencies: 221 | encodeurl "~1.0.1" 222 | escape-html "~1.0.3" 223 | parseurl "~1.3.1" 224 | send "0.15.1" 225 | 226 | setprototypeof@1.0.3: 227 | version "1.0.3" 228 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 229 | 230 | "statuses@>= 1.3.1 < 2", statuses@~1.3.1: 231 | version "1.3.1" 232 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 233 | 234 | type-is@~1.6.14: 235 | version "1.6.14" 236 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" 237 | dependencies: 238 | media-typer "0.3.0" 239 | mime-types "~2.1.13" 240 | 241 | unpipe@~1.0.0: 242 | version "1.0.0" 243 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 244 | 245 | utils-merge@1.0.0: 246 | version "1.0.0" 247 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" 248 | 249 | vary@~1.1.0: 250 | version "1.1.0" 251 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" 252 | --------------------------------------------------------------------------------