├── .gitignore ├── README.md ├── index.js ├── package.json └── src ├── BaseRequest.js ├── OTP.js └── USER.js /.gitignore: -------------------------------------------------------------------------------- 1 | main.js 2 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # New Ovoid Nodejs 3 | 4 | ![ovoid-new](https://i.ibb.co/NtXsm0X/here.png) 5 | 6 | a Node.js library for interacting with the OVO (Indonesia Digital Wallet) API. It provides functionality for fetching user balance, order history, wallet transaction history, and notification status. 7 | 8 | 9 | Updated and working : 14/06/2023 10 | 11 | Click Star (⭐) if you like this 12 | 13 | ## Installation 14 | You can install this library by running `npm install` in your terminal. 15 | 16 | ```bash 17 | npm install ovoid-new 18 | ``` 19 | ## Usage 20 | 21 | Below are some examples of how to use this library: 22 | 23 | ```javascript 24 | const {OTP,USER} = require('ovoid-new'); 25 | 26 | let otp = new OTP(); 27 | 28 | // send number must be in +62 format 29 | // example +628xxxxxxx 30 | let number = "+628xxxxx"; 31 | otp.sendOTP(number) 32 | .then(data => console.log(data)) 33 | .catch(error => console.error(error)); 34 | // will return 35 | { 36 | ref_id : "xxxxxx", 37 | device_id: "xxxxx" 38 | } 39 | 40 | // Sumbit OTP 41 | otp.submitOTP(number,device_id,otp_code,otp,ref_id) 42 | .then(data => console.log(data)) 43 | .catch(error => console.error(error)); 44 | // will return the otp token 45 | 46 | // loginSecurity 47 | const verif = await otp.loginSecurityCode(security_code,otp_token,number,device_id,otp_ref_id) 48 | .then(data => console.log(data)) 49 | .catch(error => console.error(error)); 50 | ``` 51 | 52 | Example : 53 | 54 | ```javascript 55 | const {OTP,USER} = require('ovoid-new'); 56 | async function main(){ 57 | const API = new USER(); 58 | const balance = await API.getBalance(device_id,token); 59 | const walletTrx = await API.getOrderHistory(deviceId, otpToken, page, limit, productType); 60 | 61 | } 62 | 63 | main(); 64 | ``` 65 | 66 | ## Methods 67 | 68 | ### getBalance(deviceId, otpToken) 69 | This method is used to fetch the balance of the user. It requires the deviceId and otpToken. 70 | 71 | ### getOrderHistory(deviceId, otpToken, page, limit, productType) 72 | This method fetches the order history of the user. It requires the deviceId and otpToken. You can also specify the page, limit, and productType parameters. 73 | 74 | ### getWalletTransaction(deviceId, otpToken, limit, transactionTypes) 75 | This method fetches the wallet transaction history of the user. It requires the deviceId and otpToken. You can also specify the limit and transactionTypes parameters. 76 | 77 | ### getNotifications(deviceId, otpToken) 78 | This method fetches the notification status for the user. It requires the deviceId and otpToken. 79 | 80 | # License 81 | 82 | [GPL-3.0 license](https://github.com/fdciabdul/new-ovoid-nodejs/LICENSE) 83 | 84 | # [](https://github.com/fdciabdul/new-ovoid-nodejs#code-by)Code By 85 | 86 | Abdul Muttaqin 87 | 88 | # [](https://github.com/fdciabdul/new-ovoid-nodejs#cp)CP 89 | 90 | - [cp@imtaqin.id](mailto:cp@imtaqin.id) 91 | - [taqin2731@gmail.com](mailto:taqin2731@gmail.com) 92 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const OTP = require('./src/OTP'); 2 | const USER = require('./src/USER'); 3 | 4 | module.exports = { 5 | OTP, 6 | USER 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "axios": "^1.4.0", 4 | "crypto": "^1.0.1", 5 | "uuid": "^9.0.0" 6 | }, 7 | "name": "ovoid-new", 8 | "description": "Wrapper for unofficial OVO e-wallet API", 9 | "version": "1.0.1", 10 | "main": "index.js", 11 | "devDependencies": {}, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/fdciabdul/new-ovoid-nodejs.git" 18 | }, 19 | "keywords": [ 20 | "ovo", 21 | "dana", 22 | "e-wallet" 23 | ], 24 | "author": "Abdul Muttaqin", 25 | "license": "ISC", 26 | "bugs": { 27 | "url": "https://github.com/fdciabdul/new-ovoid-nodejs/issues" 28 | }, 29 | "homepage": "https://github.com/fdciabdul/new-ovoid-nodejs#readme" 30 | } 31 | -------------------------------------------------------------------------------- /src/BaseRequest.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | 4 | class BaseRequest { 5 | constructor() { 6 | this.AGW_BASEURL = axios.create({ 7 | baseURL: 'https://agw.ovo.id/', 8 | headers: { 9 | 'Accept-Encoding': 'gzip', 10 | 'App-Version': '3.84.1', 11 | 'Client-Id': 'ovo_android', 12 | 'Connection': 'Keep-Alive', 13 | 'Content-Type': 'application/json; charset=UTF-8', 14 | 'OS': 'Android', 15 | 'OS-Version': '12', 16 | 'User-Agent': 'okhttp/4.11.0', 17 | }, 18 | }); 19 | this.API_OVO_BASE_URL = axios.create({ 20 | baseURL: 'https://api.ovo.id/', 21 | headers: { 22 | 'Accept-Encoding': 'gzip', 23 | 'App-Version': '3.84.1', 24 | 'Client-Id': 'ovo_android', 25 | 'Connection': 'Keep-Alive', 26 | 'Content-Type': 'application/json; charset=UTF-8', 27 | 'OS': 'Android', 28 | 'OS-Version': '12', 29 | 'User-Agent': 'okhttp/4.11.0', 30 | }, 31 | }); 32 | 33 | } 34 | } 35 | 36 | module.exports = BaseRequest; 37 | -------------------------------------------------------------------------------- /src/OTP.js: -------------------------------------------------------------------------------- 1 | const BaseRequest = require('./BaseRequest'); 2 | const crypto = require('crypto'); 3 | const { 4 | v4: uuidv4 5 | } = require('uuid'); 6 | const constants = require("constants"); 7 | class sendOTP extends BaseRequest { 8 | super() { 9 | this.deviceId = uuidv4(); 10 | } 11 | async sendOTP(msisdn) { 12 | const data = { 13 | channel_code: 'ovo_android', 14 | device_id: this.deviceId, 15 | msisdn, 16 | otp: { 17 | channel: 'SMS', 18 | locale: 'ID', 19 | sms_hash: 'm9mj4ctIVR8' 20 | } 21 | }; 22 | try { 23 | this.AGW_BASEURL.defaults.headers['device-id'] = this.deviceId; 24 | const response = await this.AGW_BASEURL.post('v4/api/oauth/otp/onboardingType', data); 25 | return { 26 | ref_id: response.data?.data.otp.otp_ref_id, 27 | deviceId: this.deviceId 28 | }; 29 | } catch (error) { 30 | 31 | return error.message; 32 | } 33 | } 34 | async submitOTP(msisdn, deviceId, otp, otp_ref_id) { 35 | const data = { 36 | channel_code: 'ovo_android', 37 | device_id: deviceId, 38 | msisdn, 39 | otp: { 40 | otp, 41 | otp_ref_id, 42 | type: 'LOGIN' 43 | } 44 | }; 45 | try { 46 | const response = await this.AGW_BASEURL.post('v3/user/accounts/otp/validation', data); 47 | return response.data; 48 | } catch (error) { 49 | return error.response?.data; 50 | } 51 | } 52 | 53 | async getPublicKeys(deviceId) { 54 | try { 55 | const response = await this.AGW_BASEURL.get('v3/user/public_keys'); 56 | this.AGW_BASEURL.defaults.headers['device-id'] = deviceId; 57 | return response.data; 58 | } catch (error) { 59 | 60 | return error.message; 61 | } 62 | } 63 | 64 | async encryptRSA(securityCode, deviceId, phoneNumber, otpRefId) { 65 | const publicKey = (await this.getPublicKeys(deviceId)).data.keys[0].key; 66 | const d = new Date(); 67 | const currentTimeMillies = d.getTime(); 68 | const string = "LOGIN|" + securityCode + "|" + currentTimeMillies + "|" + deviceId + "|" + phoneNumber + "|" + deviceId + "|" + otpRefId; 69 | return crypto.publicEncrypt({ 70 | key: publicKey, 71 | padding: constants.RSA_PKCS1_PADDING, 72 | }, Buffer.from(string, "utf8")).toString("base64"); 73 | } 74 | 75 | async loginSecurityCode(securityCode, otp_token, mobilePhone, otpRefId, device_id, pushId = 'XXXXXXXXXX') { 76 | this.AGW_BASEURL.defaults.headers['device-id'] = device_id; 77 | let passwordValue = await this.encryptRSA(securityCode, device_id, mobilePhone, otpRefId); 78 | let data = { 79 | "channel_code": "ovo_android", 80 | "credentials": { 81 | "otp_token": otp_token, 82 | "password": { 83 | "format": "rsa", 84 | "value": passwordValue 85 | } 86 | }, 87 | "device_id": device_id, 88 | "msisdn": mobilePhone, 89 | "push_notification_id": pushId 90 | }; 91 | try { 92 | const response = await this.AGW_BASEURL.post('v3/user/accounts/login', data); 93 | return response.data; 94 | } catch (error) { 95 | return error.message; 96 | } 97 | } 98 | } 99 | 100 | module.exports = sendOTP; -------------------------------------------------------------------------------- /src/USER.js: -------------------------------------------------------------------------------- 1 | const BaseRequest = require('./BaseRequest'); 2 | 3 | class getBalance extends BaseRequest { 4 | async getBalance(deviceId, token) { 5 | this.API_OVO_BASE_URL.defaults.headers['Device-Id'] = deviceId; 6 | this.API_OVO_BASE_URL.defaults.headers['Authorization'] = token; 7 | try { 8 | const response = await this.API_OVO_BASE_URL.get('wallet/inquiry'); 9 | return response.data; 10 | } catch (error) { 11 | 12 | return error.message; 13 | } 14 | } 15 | 16 | async getWalletTransaction(deviceId, token, limit = 5, transactionTypes = ['TRANSFER', 'EXTERNAL TRANSFER']) { 17 | this.API_OVO_BASE_URL.defaults.headers['Device-Id'] = deviceId; 18 | this.API_OVO_BASE_URL.defaults.headers['Authorization'] = token; 19 | const typesParam = transactionTypes.map(type => `transaction_type=${encodeURIComponent(type)}`).join('&'); 20 | try { 21 | const response = await this.API_OVO_BASE_URL.get(`wallet/transaction/last?limit=${limit}&${typesParam}`); 22 | return response.data; 23 | } catch (error) { 24 | 25 | return error.message; 26 | } 27 | } 28 | 29 | async getOrderHistory(deviceId, token, page = 1, limit = 15, productType = '001') { 30 | this.AGW_BASEURL.defaults.headers['Device-Id'] = deviceId; 31 | this.AGW_BASEURL.defaults.headers['Authorization'] = token; 32 | try { 33 | const response = await this.AGW_BASEURL.get(`payment/orders/v1/list?page=${page}&limit=${limit}&productType=${productType}`); 34 | return { 35 | complete : response.data.data.orders[0].complete, 36 | pending : response.data.data.orders[0].pending} 37 | } catch (error) { 38 | 39 | return error.message; 40 | } 41 | } 42 | } 43 | 44 | 45 | module.exports = getBalance; 46 | --------------------------------------------------------------------------------