├── .gitignore ├── README.md ├── app.js ├── package.json └── routes ├── requests.js └── responses.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.env -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Daraja-Node-Js-Tutorial 2 | This a repo for Tutorials on Daraja << Node Js >> 3 | 4 | Full Tutorials 5 | https://www.youtube.com/playlist?list=PLcKuwRUZRXZIKKLahxEwcYW7RAG18la3v 6 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const request = require('request') 3 | const bodyParser = require('body-parser') 4 | 5 | const app = express() 6 | app.use(bodyParser.json()) 7 | 8 | const urls = { 9 | 'stk': "", 10 | "simulate": "", 11 | "b2c": "", 12 | "base_url": "" 13 | } 14 | const maker = access_token() 15 | const headers = { 16 | "Authorization": "Bearer " + maker 17 | } 18 | 19 | 20 | app.get('/', (req, res) => { 21 | let date = new Date() 22 | let timestamp = date.getDate() + "" + "" + date.getMonth() + "" + "" + date.getFullYear() + "" + "" + date.getHours() + "" + "" + date.getMinutes() + "" + "" + date.getSeconds() 23 | 24 | res.status(200).json({ message: "We're up and running. Happy Coding", time: new Buffer.from(timestamp).toString('base64'), token: headers }) 25 | }) 26 | 27 | app.get('/access_token', access, (req, res) => { 28 | res.status(200).json({ access_token: req.access_token }) 29 | }) 30 | 31 | 32 | 33 | app.get('/register', access, (req, resp) => { 34 | let url = "https://sandbox.safaricom.co.ke/mpesa/c2b/v1/registerurl" 35 | let auth = "Bearer " + req.access_token 36 | 37 | request( 38 | { 39 | url: url, 40 | method: "POST", 41 | headers: { 42 | "Authorization": auth 43 | }, 44 | json: { 45 | "ShortCode": "600383", 46 | "ResponseType": "Complete", 47 | "ConfirmationURL": "http://197.248.86.122:801/confirmation", 48 | "ValidationURL": "http://197.248.86.122:801/validation" 49 | } 50 | }, 51 | function (error, response, body) { 52 | if (error) { console.log(error) } 53 | resp.status(200).json(body) 54 | } 55 | ) 56 | }) 57 | 58 | app.post('/confirmation', (req, res) => { 59 | console.log('....................... confirmation .............') 60 | console.log(req.body) 61 | }) 62 | 63 | app.post('/validation', (req, resp) => { 64 | console.log('....................... validation .............') 65 | console.log(req.body) 66 | }) 67 | 68 | 69 | app.get('/simulate', access, (req, res) => { 70 | let url = "https://sandbox.safaricom.co.ke/mpesa/c2b/v1/simulate" 71 | let auth = "Bearer " + req.access_token 72 | 73 | request( 74 | { 75 | url: url, 76 | method: "POST", 77 | headers: { 78 | "Authorization": auth 79 | }, 80 | json: { 81 | "ShortCode": "600383", 82 | "CommandID": "CustomerPayBillOnline", 83 | "Amount": "100", 84 | "Msisdn": "254708374149", 85 | "BillRefNumber": "TestAPI" 86 | } 87 | }, 88 | function (error, response, body) { 89 | if (error) { 90 | console.log(error) 91 | } 92 | else { 93 | res.status(200).json(body) 94 | } 95 | } 96 | ) 97 | }) 98 | 99 | app.get('/balance', access, (req, resp) => { 100 | let url = "https://sandbox.safaricom.co.ke/mpesa/accountbalance/v1/query" 101 | let auth = "Bearer " + req.access_token 102 | 103 | request( 104 | { 105 | url: url, 106 | method: "POST", 107 | headers: { 108 | "Authorization": auth 109 | }, 110 | json: { 111 | "Initiator": "apitest342", 112 | "SecurityCredential": "Q9KEnwDV/V1LmUrZHNunN40AwAw30jHMfpdTACiV9j+JofwZu0G5qrcPzxul+6nocE++U6ghFEL0E/5z/JNTWZ/pD9oAxCxOik/98IYPp+elSMMO/c/370Joh2XwkYCO5Za9dytVmlapmha5JzanJrqtFX8Vez5nDBC4LEjmgwa/+5MvL+WEBzjV4I6GNeP6hz23J+H43TjTTboeyg8JluL9myaGz68dWM7dCyd5/1QY0BqEiQSQF/W6UrXbOcK9Ac65V0+1+ptQJvreQznAosCjyUjACj35e890toDeq37RFeinM3++VFJqeD5bf5mx5FoJI/Ps0MlydwEeMo/InA==", 113 | "CommandID": "AccountBalance", 114 | "PartyA": "601342", 115 | "IdentifierType": "4", 116 | "Remarks": "bal", 117 | "QueueTimeOutURL": "http://197.248.86.122:801/bal_timeout", 118 | "ResultURL": "http://197.248.86.122:801/bal_result" 119 | } 120 | }, 121 | function (error, response, body) { 122 | if (error) { 123 | console.log(error) 124 | } 125 | else { 126 | resp.status(200).json(body) 127 | } 128 | } 129 | ) 130 | }) 131 | 132 | app.get('/stk', access, (req, res) => { 133 | const url = "https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest", 134 | auth = "Bearer " + req.access_token 135 | let date = new Date() 136 | const timestamp = date.getFullYear() + "" + "" + date.getMonth() + "" + "" + date.getDate() + "" + "" + date.getHours() + "" + "" + date.getMinutes() + "" + "" + date.getSeconds() 137 | const password = new Buffer.from('174379' + 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919' + timestamp).toString('base64') 138 | 139 | request( 140 | { 141 | url: url, 142 | method: "POST", 143 | headers: { 144 | "Authorization": auth 145 | }, 146 | json: { 147 | "BusinessShortCode": "174379", 148 | "Password": password, 149 | "Timestamp": timestamp, 150 | "TransactionType": "CustomerPayBillOnline", 151 | "Amount": "1", 152 | "PartyA": "254716437799", 153 | "PartyB": "174379", 154 | "PhoneNumber": "254716437799", 155 | "CallBackURL": "http://197.248.86.122:801/stk_callback", 156 | "AccountReference": "Test", 157 | "TransactionDesc": "TestPay" 158 | } 159 | }, 160 | function (error, response, body) { 161 | if (error) { 162 | console.log(error) 163 | } 164 | else { 165 | res.status(200).json(body) 166 | } 167 | } 168 | ) 169 | }) 170 | 171 | app.get('/b2c', access, (req, res) => { 172 | const url = 'https://sandbox.safaricom.co.ke/mpesa/b2c/v1/paymentrequest', 173 | auth = 'Bearer ' + req.access_token 174 | 175 | request({ 176 | method: "POST", 177 | url: url, 178 | headers: { 179 | "Authorization": auth 180 | }, 181 | json: { 182 | "InitiatorName": "apitest342", 183 | "SecurityCredential": "Q9KEnwDV/V1LmUrZHNunN40AwAw30jHMfpdTACiV9j+JofwZu0G5qrcPzxul+6nocE++U6ghFEL0E/5z/JNTWZ/pD9oAxCxOik/98IYPp+elSMMO/c/370Joh2XwkYCO5Za9dytVmlapmha5JzanJrqtFX8Vez5nDBC4LEjmgwa/+5MvL+WEBzjV4I6GNeP6hz23J+H43TjTTboeyg8JluL9myaGz68dWM7dCyd5/1QY0BqEiQSQF/W6UrXbOcK9Ac65V0+1+ptQJvreQznAosCjyUjACj35e890toDeq37RFeinM3++VFJqeD5bf5mx5FoJI/Ps0MlydwEeMo/InA==", 184 | "CommandID": "BusinessPayment", 185 | "Amount": "200", 186 | "PartyA": "601342", 187 | "PartyB": "254708374149", 188 | "Remarks": "please pay", 189 | "QueueTimeOutURL": "http://197.248.86.122:801/b2c_timeout_url", 190 | "ResultURL": "http://197.248.86.122:801/b2c_result_url", 191 | "Occasion": "endmonth" 192 | } 193 | }, 194 | function (error, response, body) { 195 | if (error) { 196 | console.log(error) 197 | } 198 | else { 199 | res.status(200).json(body) 200 | } 201 | } 202 | ) 203 | }) 204 | 205 | app.get('/reverse', access, (req, res) => { 206 | const url = 'https://sandbox.safaricom.co.ke/mpesa/reversal/v1/request', 207 | auth = 'Bearer ' + req.access_token 208 | 209 | request({ 210 | method: "POST", 211 | url: url, 212 | headers: { 213 | "Authorization": auth 214 | }, 215 | json: { 216 | "Initiator": "apitest342", 217 | "SecurityCredential":"Q9KEnwDV/V1LmUrZHNunN40AwAw30jHMfpdTACiV9j+JofwZu0G5qrcPzxul+6nocE++U6ghFEL0E/5z/JNTWZ/pD9oAxCxOik/98IYPp+elSMMO/c/370Joh2XwkYCO5Za9dytVmlapmha5JzanJrqtFX8Vez5nDBC4LEjmgwa/+5MvL+WEBzjV4I6GNeP6hz23J+H43TjTTboeyg8JluL9myaGz68dWM7dCyd5/1QY0BqEiQSQF/W6UrXbOcK9Ac65V0+1+ptQJvreQznAosCjyUjACj35e890toDeq37RFeinM3++VFJqeD5bf5mx5FoJI/Ps0MlydwEeMo/InA==", 218 | "CommandID":"TransactionReversal", 219 | "TransactionID":"NLJ11HAY8V", 220 | "Amount":"100", 221 | "ReceiverParty":"601342", 222 | "RecieverIdentifierType":"11", 223 | "ResultURL":"http://197.248.86.122:801/reverse_result_url", 224 | "QueueTimeOutURL":"http://197.248.86.122:801/reverse_timeout_url", 225 | "Remarks":"Wrong Num", 226 | "Occasion":"sent wrongly" 227 | } 228 | }, 229 | function (error, response, body) { 230 | if (error) { 231 | console.log(error) 232 | } 233 | else { 234 | res.status(200).json(body) 235 | } 236 | } 237 | ) 238 | }) 239 | 240 | app.post('/reverse_result_url', (req, res) => { 241 | console.log("--------------------Reverse Result -----------------") 242 | console.log(JSON.stringify(req.body.Result.ResultParameters)) 243 | }) 244 | 245 | app.post('/reverse_timeout_url', (req, res) => { 246 | console.log("-------------------- Reverse Timeout -----------------") 247 | console.log(req.body) 248 | }) 249 | 250 | app.post('/b2c_result_url', (req, res) => { 251 | console.log("-------------------- B2C Result -----------------") 252 | console.log(JSON.stringify(req.body.Result)) 253 | }) 254 | 255 | app.post('/b2c_timeout_url', (req, res) => { 256 | console.log("-------------------- B2C Timeout -----------------") 257 | console.log(req.body) 258 | }) 259 | 260 | app.post('/stk_callback', (req, res) => { 261 | console.log('.......... STK Callback ..................') 262 | console.log(JSON.stringify(req.body.Body.stkCallback)) 263 | }) 264 | 265 | app.post('/bal_result', (req, resp) => { 266 | console.log('.......... Account Balance ..................') 267 | console.log(req.body) 268 | }) 269 | 270 | app.post('/bal_timeout', (req, resp) => { 271 | console.log('.......... Timeout..................') 272 | console.log(req.body) 273 | }) 274 | 275 | function access(req, res, next) { 276 | // access token 277 | let url = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials" 278 | let auth = new Buffer.from("85MRpefVx4EdgWshx8cTrBt16ssYRxTg:JE9GqoasQcKL9e2W").toString('base64'); 279 | 280 | request( 281 | { 282 | url: url, 283 | headers: { 284 | "Authorization": "Basic " + auth 285 | } 286 | }, 287 | (error, response, body) => { 288 | if (error) { 289 | console.log(error) 290 | } 291 | else { 292 | // let resp = 293 | req.access_token = JSON.parse(body).access_token 294 | next() 295 | } 296 | } 297 | ) 298 | } 299 | 300 | 301 | function access_token() { 302 | // access token 303 | let url = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials" 304 | let auth = new Buffer.from("85MRpefVx4EdgWshx8cTrBt16ssYRxTg:JE9GqoasQcKL9e2W").toString('base64'); 305 | 306 | request( 307 | { 308 | url: url, 309 | headers: { 310 | "Authorization": "Basic " + auth 311 | } 312 | }, 313 | (error, response, body) => { 314 | if (error) { 315 | console.log(error) 316 | } 317 | else { 318 | // let resp = 319 | return JSON.parse(body).access_token 320 | } 321 | } 322 | ) 323 | } 324 | 325 | app.listen(80, (err, live) => { 326 | if (err) { 327 | console.error(err) 328 | } 329 | console.log("Server running on port 80") 330 | }); 331 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "daraja-node", 3 | "version": "1.0.0", 4 | "description": "A simple project on Node Js consuming Daraja API", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon app.js" 8 | }, 9 | "keywords": [ 10 | "m-pesa", 11 | "safaricom", 12 | "api", 13 | "m-pesa", 14 | "api" 15 | ], 16 | "author": "Benson Njunge", 17 | "license": "ISC" 18 | } 19 | -------------------------------------------------------------------------------- /routes/requests.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const route = express.Router(); 3 | const access_token = require('../app/access_token') 4 | const register_url = require('../app/register_url') 5 | 6 | route.get('/', (req, res) => { 7 | res.send("Hello World") 8 | }) 9 | 10 | route.get('/access_token', access_token) 11 | 12 | module.exports = route; -------------------------------------------------------------------------------- /routes/responses.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | 3 | const routes = express.Router(); 4 | 5 | routes.get('/', (req, resp) => { 6 | resp.send("We are on responses") 7 | }) 8 | 9 | 10 | module.exports = routes; --------------------------------------------------------------------------------