├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── LICENSE ├── README.md ├── composer.json ├── example.php ├── example ├── QrisPay.php ├── getAuthToken.php ├── getBankList.php ├── transactionHistory.php ├── transferBank.php └── transferOvo.php └── src └── Ovo.php /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ANAMPEDIA 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![namdevel-ovoid-api.png](https://i.postimg.cc/nV1VkLDk/namdevel-ovoid-api.png "namdevel-ovoid-api.png") 2 | 3 | [![API](https://img.shields.io/badge/OVO%20API-March%2004%2C%202022-36ade1.svg)](https://www.ovo.id/features) 4 | [![CodeFactor](https://www.codefactor.io/repository/github/namdevel/ovoid-api/badge)](https://www.codefactor.io/repository/github/namdevel/ovoid-api) 5 | [![GitHub issues](https://img.shields.io/github/issues/namdevel/ovoid-API)](https://github.com/namdevel/ovoid-API/issues) 6 | [![GitHub forks](https://img.shields.io/github/forks/namdevel/ovoid-API)](https://github.com/namdevel/ovoid-API/network) 7 | [![GitHub stars](https://img.shields.io/github/stars/namdevel/ovoid-API)](https://github.com/namdevel/ovoid-API/stargazers) 8 | [![GitHub license](https://img.shields.io/github/license/namdevel/ovoid-API)](https://github.com/namdevel/ovoid-API/blob/master/LICENSE) 9 | [![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fnamdevel%2Fovoid-API&count_bg=%23F30000&title_bg=%23555555&icon=dev-dot-to.svg&icon_color=%23E7E7E7&title=VIEWS&edge_flat=false)](https://hits.seeyoufarm.com) 10 | 11 | Compliant with the March 04, 2022 OVO API update (version 3.54.0) 12 | 13 | :coffee: Buy Me a Coffee : https://trakteer.id/namdevel/tip 14 | 15 | Installation 16 | ------------ 17 | ``` 18 | composer require namdevel/ovoid-api 19 | ``` 20 | 21 | Features 22 | ------------ 23 | - [x] Qris Payment `NEW` 24 | - [x] transferBank 25 | - [x] transferOvo 26 | - [x] billerPay 27 | - [x] sendOtp 28 | - [x] OTPVerify 29 | - [x] getAuthToken 30 | - [x] getLastTransactions 31 | - [x] getFavoriteTransfer 32 | - [x] getEmail 33 | - [x] transactionHistory 34 | - [x] walletInquiry 35 | - [x] getOvoCash 36 | - [x] getOvoCashCardNumber 37 | - [x] getOvoPointsCardNumber 38 | - [x] getOvoPoints 39 | - [x] getPointDetails 40 | - [x] getBillerList 41 | - [x] getBillerCategory 42 | - [x] generateSignature (for transfer more than 2 times) 43 | - [x] getDenominations 44 | - [x] isOVO 45 | - [x] getBankList 46 | - [x] getUnreadNotifications 47 | - [x] getAllNotifications 48 | - [x] getInvestment 49 | - [x] getTransactionDetails 50 | 51 | License 52 | ------------ 53 | 54 | This open-source software is distributed under the MIT License. See LICENSE.md 55 | 56 | Contributing 57 | ------------ 58 | 59 | All kinds of contributions are welcome - code, tests, documentation, bug reports, new features, etc... 60 | 61 | * Send feedbacks. 62 | * Submit bug reports. 63 | * Write/Edit the documents. 64 | * Fix bugs or add new features. 65 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "namdevel/ovoid-api", 3 | "description": "Un-official OVO ID API Wrapper", 4 | "type": "library", 5 | "license": "MIT", 6 | "autoload": { 7 | "psr-4": { 8 | "Namdevel\\": "src/" 9 | } 10 | }, 11 | "authors": [ 12 | { 13 | "name": "namdevel", 14 | "email": "namdevel@gmail.com" 15 | } 16 | ], 17 | "minimum-stability": "dev", 18 | "require": {} 19 | } 20 | -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | getLastTransactions(); // get 5 last transaction 10 | 11 | echo $app->getFavoriteTransfer(); // get favorite transfer 12 | 13 | echo $app->getEmail(); // get account email 14 | 15 | echo $app->transactionHistory(); // get transaction history 16 | 17 | echo $app->walletInquiry(); // wallet inquiry 18 | 19 | echo $app->getOvoCash(); // get ovo balance 20 | 21 | echo $app->getOvoCashCardNumber(); // get ovo cash card number 22 | 23 | echo $app->getOvoPointsCardNumber(); // get ovo point card number 24 | 25 | echo $app->getOvoPoints(); // get ovo point balance 26 | 27 | echo $app->getPointDetails(); // get ovo point history 28 | 29 | echo $app->getBillerList(); // get biller list 30 | 31 | echo $app->getBillerCategory(''); // get biller category 32 | 33 | echo $app->getDenominations(''); // get denomination 34 | 35 | echo $app->getBankList(); // get bank list 36 | 37 | echo $app->getUnreadNotifications(); // get total unread notification 38 | 39 | echo $app->getAllNotifications(); // get all notifications 40 | 41 | echo $app->getInvestment(); // get investment data 42 | 43 | echo $app->isOVO('', ''); // ovo account validate 44 | 45 | echo $app->getTransactionDetails('', ''); // get transaction details -------------------------------------------------------------------------------- /example/QrisPay.php: -------------------------------------------------------------------------------- 1 | generateTrxId($amount_to_pay, 'PAY_TRX_ID'))->trxId; // generate transaction id , PAY_TRX_ID = action mark for billpay and qris pay 15 | $unlock = json_decode($app->unlockAndValidateTrxId($amount_to_pay, $trx_id, $ovo_pin)); // unlock and validate transaction id 16 | 17 | if($unlock->isAuthorized){ // is unlock authorized 18 | echo $app->QrisPay($amount_to_pay, $trx_id, $qrid); 19 | } -------------------------------------------------------------------------------- /example/getAuthToken.php: -------------------------------------------------------------------------------- 1 | sendOtp('+628XXXXXXXXXX'); 11 | /* 12 | @ Step 2 13 | */ 14 | echo $app->OTPVerify('+628XXXXXXXXXX', '', ''); 15 | /* 16 | @ Step 3 17 | */ 18 | echo $app->getAuthToken('+628XXXXXXXXXX', '', '', ''); 19 | -------------------------------------------------------------------------------- /example/getBankList.php: -------------------------------------------------------------------------------- 1 | getBankList(); -------------------------------------------------------------------------------- /example/transactionHistory.php: -------------------------------------------------------------------------------- 1 | transactionHistory(); -------------------------------------------------------------------------------- /example/transferBank.php: -------------------------------------------------------------------------------- 1 | transferBankInquiry('', '', $amount_to_pay, $message = ""); // inquiry request (get bank account details) 13 | 14 | $detail = json_decode($inquiry); 15 | 16 | $trx_id = json_decode($app->generateTrxId($amount_to_pay, 'OVO Cash'))->trxId; // generate transaction id , OVO Cash = action mark for tf OVO & Tf Bank 17 | $unlock = json_decode($app->unlockAndValidateTrxId($amount_to_pay, $trx_id, $ovo_pin)); // unlock and validate transaction id 18 | 19 | if($unlock->isAuthorized){ // is unlock authorized 20 | echo $app->transferBankDirect($detail->bankCode, $detail->accountNo, $detail->bankName, $detail->accountName, $trx_id, $amount_to_pay, $notes = ""); 21 | } 22 | -------------------------------------------------------------------------------- /example/transferOvo.php: -------------------------------------------------------------------------------- 1 | generateTrxId($amount_to_pay, 'OVO Cash'))->trxId; // generate transaction id , OVO Cash = action mark for tf OVO & Tf Bank 15 | $unlock = json_decode($app->unlockAndValidateTrxId($amount_to_pay, $trx_id, $ovo_pin)); // unlock and validate transaction id 16 | 17 | if($unlock->isAuthorized){ // is unlock authorized 18 | echo $app->transferOVO($amount_to_pay, $to, $trx_id, $message = ""); 19 | } -------------------------------------------------------------------------------- /src/Ovo.php: -------------------------------------------------------------------------------- 1 | auth_token = $auth_token; 38 | } 39 | } 40 | 41 | /* 42 | @ generateUUIDV4 43 | @ generate random UUIDV4 for device ID 44 | */ 45 | public function generateUUIDV4() 46 | { 47 | $data = random_bytes(16); 48 | $data[6] = chr((ord($data[6]) & 0x0f) | 0x40); 49 | $data[8] = chr((ord($data[8]) & 0x3f) | 0x80); 50 | return strtoupper(vsprintf("%s%s-%s-%s-%s-%s%s%s", str_split(bin2hex($data), 4))); 51 | } 52 | 53 | /* 54 | @ generateRandomSHA256 55 | @ generate random SHA256 hash for push notification ID 56 | */ 57 | public function generateRandomSHA256() 58 | { 59 | return hash_hmac("sha256", time(), "ovo-apps"); 60 | } 61 | 62 | /* 63 | @ headers 64 | @ OVO cutsom headers 65 | */ 66 | protected function headers($bearer = false) 67 | { 68 | $headers = array( 69 | 'content-type: application/json', 70 | 'accept: */*', 71 | 'app-version: ' . self::app_version, 72 | 'client-id: ' . self::client_id, 73 | 'device-id: ' . self::device_id, 74 | 'os: ' . self::os, 75 | 'user-agent: ' . self::user_agent 76 | ); 77 | 78 | if ($this->auth_token) { 79 | array_push($headers, 'authorization: ' . $bearer . ' ' . $this->auth_token); 80 | } 81 | 82 | return $headers; 83 | } 84 | 85 | /* 86 | @ sendOtp 87 | @ param (string phone_number) 88 | @ AGW ENDPOINT POST("/v3/user/accounts/otp") 89 | */ 90 | public function sendOtp($phone_number) 91 | { 92 | $field = array( 93 | 'msisdn' => $phone_number, 94 | 'device_id' => self::device_id, 95 | 'otp' => array( 96 | 'locale' => 'EN', 97 | 'sms_hash' => 'abc' 98 | ), 99 | 'channel_code' => 'ovo_ios' 100 | ); 101 | 102 | return self::request(self::AGW_API . '/v3/user/accounts/otp', $field, $this->headers()); 103 | } 104 | 105 | /* 106 | @ OTPVerify 107 | @ param (string phone_number, string otp_ref_id, string otp_code) 108 | @ AGW ENDPOINT POST("/v3/user/accounts/otp/validation") 109 | */ 110 | public function OTPVerify($phone_number, $otp_ref_id, $otp_code) 111 | { 112 | $field = array( 113 | 'channel_code' => 'ovo_ios', 114 | 'otp' => array( 115 | 'otp_ref_id' => $otp_ref_id, 116 | 'otp' => $otp_code, 117 | 'type' => 'LOGIN' 118 | ), 119 | 'msisdn' => $phone_number, 120 | 'device_id' => self::device_id 121 | ); 122 | 123 | return self::request(self::AGW_API . '/v3/user/accounts/otp/validation', $field, $this->headers()); 124 | } 125 | 126 | /* 127 | @ getAuthToken 128 | @ param (string phone_number, string otp_ref_id, string otp_token, string security_code) 129 | @ AGW ENDPOINT POST("/v3/user/accounts/login") 130 | */ 131 | public function getAuthToken($phone_number, $otp_ref_id, $otp_token, $security_code) 132 | { 133 | $field = array( 134 | 'msisdn' => $phone_number, 135 | 'device_id' => self::device_id, 136 | 'push_notification_id' => self::push_notification_id, 137 | 'credentials' => array( 138 | 'otp_token' => $otp_token, 139 | 'password' => array( 140 | 'value' => self::hashPassword($phone_number, $otp_ref_id, $security_code), 141 | 'format' => 'rsa' 142 | ) 143 | ), 144 | 'channel_code' => 'ovo_ios' 145 | ); 146 | 147 | return self::request(self::AGW_API . '/v3/user/accounts/login', $field, $this->headers()); 148 | } 149 | 150 | /* 151 | @ getPublicKeys 152 | @ AGW ENDPOINT GET("/v3/user/public_keys") 153 | */ 154 | public function getPublicKeys() 155 | { 156 | return self::request(self::AGW_API . '/v3/user/public_keys', false, $this->headers()); 157 | } 158 | 159 | /* 160 | @ getLastTransactions 161 | @ param (int limit) 162 | @ BASE ENDPOINT GET("/wallet/transaction/last") 163 | */ 164 | public function getLastTransactions($limit = 5) 165 | { 166 | return self::request(self::BASE_API . '/wallet/transaction/last?limit=' . $limit . '&transaction_type=TRANSFER&transaction_type=EXTERNAL%20TRANSFER', false, $this->headers()); 167 | } 168 | 169 | /* 170 | @ getTransactionDetails 171 | @ param (string merchant_id. string merchant_invoice) 172 | @ BASE ENDPOINT GET("/wallet/transaction/{merchant_id}/{merchant_invoice}") 173 | */ 174 | public function getTransactionDetails($merchant_id, $merchant_invoice) 175 | { 176 | return self::request(self::BASE_API . '/wallet/transaction/' . $merchant_id . '/' . $merchant_invoice . '', false, $this->headers()); 177 | } 178 | 179 | /* 180 | @ getFavoriteTransfer 181 | @ AWS ENDPOINT GET("/user-profiling/favorite-transfer") 182 | */ 183 | public function getFavoriteTransfer() 184 | { 185 | return self::request(self::AWS_API . '/user-profiling/favorite-transfer', false, $this->headers()); 186 | } 187 | 188 | /* 189 | @ hashPassword 190 | @ param (string phone_number, string otp_ref_id, string security_code) 191 | @ return base64_encoded string 192 | */ 193 | protected function hashPassword($phone_number, $otp_ref_id, $security_code) 194 | { 195 | $rsa_key = self::parse(self::getPublicKeys(), true)['data']['keys'][0]['key']; 196 | $data = join("|", array( 197 | 'LOGIN', 198 | $security_code, 199 | time(), 200 | self::device_id, 201 | $phone_number, 202 | self::device_id, 203 | $otp_ref_id 204 | )); 205 | openssl_public_encrypt($data, $output, $rsa_key); 206 | return base64_encode($output); 207 | } 208 | 209 | /* 210 | @ getEmail 211 | @ return account email detail 212 | */ 213 | public function getEmail() 214 | { 215 | return self::request(self::AGW_API . '/v3/user/accounts/email', false, $this->headers()); 216 | } 217 | 218 | /* 219 | @ transactionHistory 220 | @ param (int page, int limit) 221 | @ AGW ENDPOINT GET("/payment/orders/v1/list") 222 | */ 223 | public function transactionHistory($page = 1, $limit = 10) 224 | { 225 | return self::request(self::AGW_API . "/payment/orders/v1/list?limit=$limit&page=$page", false, $this->headers('Bearer')); 226 | } 227 | 228 | /* 229 | @ walletInquiry 230 | @ BASE ENDPOINT GET("/wallet/inquiry") 231 | */ 232 | public function walletInquiry() 233 | { 234 | return self::request(self::BASE_API . '/wallet/inquiry', false, $this->headers()); 235 | } 236 | 237 | /* 238 | @ getOvoCash (Ovo Balance) 239 | @ parse self::walletInquiry() 240 | */ 241 | public function getOvoCash() 242 | { 243 | return self::parse(self::walletInquiry(), false)->data->{'001'}->card_balance; 244 | } 245 | 246 | /* 247 | @ getOvoCashCardNumber (Ovo Cash) 248 | @ parse self::walletInquiry() 249 | */ 250 | public function getOvoCashCardNumber() 251 | { 252 | return self::parse(self::walletInquiry(), false)->data->{'001'}->card_no; 253 | } 254 | 255 | /* 256 | @ getOvoPointsCardNumber (Ovo Points) 257 | @ parse self::walletInquiry() 258 | */ 259 | public function getOvoPointsCardNumber() 260 | { 261 | return self::parse(self::walletInquiry(), false)->data->{'600'}->card_no; 262 | } 263 | 264 | /* 265 | @ getOvoPoints 266 | @ parse self::walletInquiry() 267 | */ 268 | public function getOvoPoints() 269 | { 270 | return self::parse(self::walletInquiry(), false)->data->{'600'}->card_balance; 271 | } 272 | 273 | /* 274 | @ getPointDetails 275 | @ AGW ENDPOINT GET("/api/v1/get-expired-webview") 276 | */ 277 | public function getPointDetails() 278 | { 279 | $json = base64_decode(json_decode(self::getHmac())->encrypted_string); 280 | $json = json_decode($json); 281 | $this->hmac_hash = $json->hmac; 282 | $this->hmac_hash_random = $json->random; 283 | return self::request(self::AGW_API . "/api/v1/get-expired-webview", false, self::commander_headers()); 284 | } 285 | 286 | /* 287 | @ getHmac 288 | @ GET("https://commander.ovo.id/api/v1/get-expired-webview") 289 | */ 290 | protected function getHmac() 291 | { 292 | return self::request("https://commander.ovo.id/api/v1/auth/hmac?type=1&encoded=", false, self::commander_headers()); 293 | } 294 | 295 | /* 296 | @ getBillerList (get category or biller data) 297 | @ AWS ENDPOINT GET("/gpdm/ovo/1/v1/billpay/catalogue/getCategories") 298 | */ 299 | public function getBillerList() 300 | { 301 | return self::request(self::AWS_API . "/gpdm/ovo/1/v1/billpay/catalogue/getCategories?categoryID=0&level=1", false, $this->headers()); 302 | } 303 | 304 | /* 305 | @ getBillerCategory (get biller by category ID) 306 | @ param (int category_id) 307 | @ AWS ENDPOINT GET("/gpdm/ovo/ID/v2/billpay/get-billers") 308 | */ 309 | public function getBillerCategory($category_id) 310 | { 311 | return self::request(self::AWS_API . "/gpdm/ovo/ID/v2/billpay/get-billers?categoryID={$category_id}", false, $this->headers()); 312 | } 313 | 314 | /* 315 | @ getDenominations 316 | @ param (int product_id) 317 | @ AWS ENDPOINT GET("/gpdm/ovo/ID/v1/billpay/get-denominations/{product_id}") 318 | */ 319 | public function getDenominations($product_id) 320 | { 321 | return self::request(self::AWS_API . "/gpdm/ovo/ID/v1/billpay/get-denominations/{$product_id}", false, $this->headers()); 322 | } 323 | 324 | /* 325 | @ getBankList 326 | @ BASE ENDPOINT GET("/v1.0/reference/master/ref_bank") 327 | */ 328 | public function getBankList() 329 | { 330 | return self::request(self::BASE_API . "/v1.0/reference/master/ref_bank", false, $this->headers()); 331 | } 332 | 333 | /* 334 | @ getUnreadNotifications 335 | @ BASE ENDPOINT GET("/v1.0/notification/status/count/UNREAD") 336 | */ 337 | public function getUnreadNotifications() 338 | { 339 | return self::request(self::BASE_API . "/v1.0/notification/status/count/UNREAD", false, $this->headers()); 340 | } 341 | 342 | /* 343 | @ getAllNotifications 344 | @ BASE ENDPOINT GET("/v1.0/notification/status/all") 345 | */ 346 | public function getAllNotifications() 347 | { 348 | return self::request(self::BASE_API . "/v1.0/notification/status/all", false, $this->headers()); 349 | } 350 | 351 | /* 352 | @ getInvestment 353 | @ GET("https://investment.ovo.id/customer") 354 | */ 355 | public function getInvestment() 356 | { 357 | return self::request("https://investment.ovo.id/customer", false, $this->headers()); 358 | } 359 | 360 | /* 361 | @ billerInquiry 362 | @ param (string phone_number, string otp_ref_id, string otp_code) 363 | @ AWS ENDPOINT POST("/gpdm/ovo/ID/v2/billpay/inquiry") 364 | */ 365 | public function billerInquiry($biller_id, $product_id, $denomination_id, $customer_id) 366 | { 367 | $field = array( 368 | 'product_id' => $product_id, 369 | 'biller_id' => $biller_id, 370 | 'customer_number' => $customer_id, 371 | 'denomination_id' => $denomination_id, 372 | 'period' => 0, 373 | 'payment_method' => array( 374 | '001', 375 | '600', 376 | 'SPLIT' 377 | ), 378 | 'customer_id' => $customer_id, 379 | 'phone_number' => $customer_id 380 | ); 381 | 382 | return self::request(self::AWS_API . '/gpdm/ovo/ID/v2/billpay/inquiry?isFavorite=false', $field, $this->headers()); 383 | } 384 | 385 | /* 386 | @ billerPay 387 | @ param (string biller_id, string product_id, string order_id, int amount, string customer_id) 388 | @ AWS ENDPOINT POST("/gpdm/ovo/ID/v1/billpay/pay") 389 | */ 390 | public function billerPay($biller_id, $product_id, $order_id, $amount, $customer_id) 391 | { 392 | $field = array( 393 | "bundling_request" => array( 394 | array( 395 | "product_id" => $product_id, 396 | "biller_id" => $biller_id, 397 | "order_id" => $order_id, 398 | "customer_id" => $customer_id, 399 | "parent_id" => "", 400 | "payment" => array( 401 | array( 402 | "amount" => (int) $amount, 403 | "card_type" => "001" 404 | ), 405 | array( 406 | "card_type" => "600", 407 | "amount" => 0 408 | ) 409 | ) 410 | ) 411 | ), 412 | "phone_number" => $customer_id 413 | ); 414 | 415 | return self::request(self::AWS_API . '/gpdm/ovo/ID/v1/billpay/pay', $field, $this->headers()); 416 | } 417 | 418 | /* 419 | @ isOvo 420 | @ param (int amount, string phone_number) 421 | @ BASE ENDPOINT POST("/v1.1/api/auth/customer/isOVO") 422 | */ 423 | public function isOVO($amount, $phone_number) 424 | { 425 | $field = array( 426 | 'amount' => $amount, 427 | 'mobile' => $phone_number 428 | ); 429 | 430 | return self::request(self::BASE_API . '/v1.1/api/auth/customer/isOVO', $field, $this->headers()); 431 | } 432 | 433 | /* 434 | @ generateTrxId 435 | @ param (int amount, string action_mark) 436 | @ BASE ENDPOINT POST("/v1.0/api/auth/customer/genTrxId") 437 | */ 438 | public function generateTrxId($amount, $action_mark = "OVO Cash") 439 | { 440 | $field = array( 441 | 'amount' => $amount, 442 | 'actionMark' => $action_mark 443 | ); 444 | 445 | return self::request(self::BASE_API . '/v1.0/api/auth/customer/genTrxId', $field, $this->headers()); 446 | } 447 | 448 | /* 449 | @ generateSignature 450 | @ param (int amount, string trx_id) 451 | @ generate unlockAndValidateTrxId signature 452 | */ 453 | protected function generateSignature($amount, $trx_id) 454 | { 455 | return sha1(join('||', array( 456 | $trx_id, 457 | $amount, 458 | self::device_id 459 | ))); 460 | } 461 | 462 | /* 463 | @ unlockAndValidateTrxId 464 | @ param (int amount, string trx_id, string security_code) 465 | @ BASE ENDPOINT POST("/v1.0/api/auth/customer/genTrxId") 466 | */ 467 | public function unlockAndValidateTrxId($amount, $trx_id, $security_code) 468 | { 469 | $field = array( 470 | 'trxId' => $trx_id, 471 | 'securityCode' => $security_code, 472 | 'appVersion' => self::app_version, 473 | 'signature' => self::generateSignature($amount, $trx_id) 474 | ); 475 | 476 | return self::request(self::BASE_API . '/v1.0/api/auth/customer/unlockAndValidateTrxId', $field, $this->headers()); 477 | } 478 | 479 | /* 480 | @ transferOVO 481 | @ param (int/string amount, string phone_number, string, trx_id, string message) 482 | @ BASE ENDPOINT POST("/v1.0/api/customers/transfer") 483 | */ 484 | public function transferOVO($amount, $phone_number, $trx_id, $message = "") 485 | { 486 | $field = array( 487 | 'amount' => $amount, 488 | 'to' => $phone_number, 489 | 'trxId' => $trx_id, 490 | 'message' => $message 491 | ); 492 | 493 | return self::request(self::BASE_API . '/v1.0/api/customers/transfer', $field, $this->headers()); 494 | } 495 | 496 | /* 497 | @ transferBankInquiry 498 | @ param (string bank_code, string bank_number, string amount, string message) 499 | @ BASE ENDPOINT POST("/transfer/inquiry") 500 | */ 501 | public function transferBankInquiry($bank_code, $bank_number, $amount, $message = "") 502 | { 503 | $field = array( 504 | 'bankCode' => $bank_code, 505 | 'accountNo' => $bank_number, 506 | 'amount' => (string) $amount, 507 | 'message' => $message 508 | ); 509 | 510 | return self::request(self::BASE_API . '/transfer/inquiry/', $field, $this->headers()); 511 | } 512 | 513 | /* 514 | @ transferBankDirect 515 | @ param (string bank_code, string bank_number, string amount, string notes) 516 | @ BASE ENDPOINT POST("/transfer/direct") 517 | */ 518 | public function transferBankDirect($bank_code, $bank_number, $bank_name, $bank_account_name, $trx_id, $amount, $notes = "") 519 | { 520 | $field = array( 521 | 'bankCode' => $bank_code, 522 | 'accountNo' => self::getOvoCashCardNumber(), 523 | 'amount' => (string) $amount, 524 | 'accountNoDestination' => $bank_number, 525 | 'bankName' => $bank_name, 526 | 'accountName' => $bank_account_name, 527 | 'notes' => $notes, 528 | 'transactionId' => $trx_id 529 | ); 530 | 531 | return self::request(self::BASE_API . '/transfer/direct', $field, $this->headers()); 532 | } 533 | 534 | /* 535 | @ QrisPay 536 | @ param (int amount, string trx_id, string qrid) 537 | @ BASE ENDPOINT POST("/wallet/purchase/qr") 538 | */ 539 | public function QrisPay($amount, $trx_id, $qrid) 540 | { 541 | $field = array( 542 | 'qrPayload' => $qrid, 543 | 'locationInfo' => array( 544 | 'accuracy' => 11.00483309472351, 545 | 'verticalAccuracy' => 3, 546 | 'longitude' => 84.90665207978246, 547 | 'heading' => 11.704396994254495, 548 | 'latitude' => -9.432921591875759, 549 | 'altitude' => 84.28827400936305, 550 | 'speed' => 0.11528167128562927 551 | ), 552 | 'deviceInfo' => array( 553 | 'deviceBrand' => 'Apple', 554 | 'deviceModel' => 'iPhone', 555 | 'appVersion' => self::app_version, 556 | 'deviceToken' => self::push_notification_id 557 | ), 558 | 'paymentDetail' => array( 559 | array( 560 | 'amount' => $amount, 561 | 'id' => '001', 562 | 'name' => 'OVO Cash' 563 | ) 564 | ), 565 | 'transactionId' => $trx_id, 566 | 'appsource' => 'OVO-APPS' 567 | ); 568 | 569 | return self::request(self::BASE_API . '/wallet/purchase/qr?qrid=' . urlencode($qrid), $field, $this->headers()); 570 | } 571 | 572 | /* 573 | @ parse 574 | @ parse JSON response 575 | */ 576 | public function parse($json, $true = true) 577 | { 578 | return json_decode($json, $true); 579 | } 580 | 581 | /* 582 | @ Request 583 | @ Curl http request 584 | */ 585 | protected function request($url, $post = false, $headers = false) 586 | { 587 | $ch = curl_init(); 588 | 589 | curl_setopt_array($ch, array( 590 | CURLOPT_URL => $url, 591 | CURLOPT_RETURNTRANSFER => 1, 592 | CURLOPT_SSL_VERIFYHOST => 0, 593 | CURLOPT_SSL_VERIFYPEER => 0 594 | )); 595 | 596 | if ($post) { 597 | curl_setopt($ch, CURLOPT_POST, 1); 598 | curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post)); 599 | } 600 | 601 | if ($headers) { 602 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 603 | } 604 | 605 | $result = curl_exec($ch); 606 | curl_close($ch); 607 | return $result; 608 | } 609 | 610 | /* 611 | @ commander API headers 612 | @ OVO Commander cutsom headers 613 | */ 614 | protected function commander_headers() 615 | { 616 | $headers = array( 617 | 'accept: application/json, text/plain, */*', 618 | 'app-id: webview-pointexpiry', 619 | 'client-id: ' . self::client_id, 620 | 'accept-language: id', 621 | 'service: police', 622 | 'origin: https://webview.ovo.id', 623 | 'user-agent: ' . self::user_agent, 624 | 'referer: https://webview.ovo.id/pointexpiry?version=3.43.0' 625 | ); 626 | 627 | if ($this->auth_token) { 628 | array_push($headers, 'authorization: Bearer ' . $this->auth_token); 629 | } 630 | 631 | if ($this->hmac_hash) { 632 | array_push($headers, 'hmac: ' . $this->hmac_hash); 633 | } 634 | 635 | if ($this->hmac_hash_random) { 636 | array_push($headers, 'random: ' . $this->hmac_hash_random); 637 | } 638 | 639 | return $headers; 640 | } 641 | } 642 | --------------------------------------------------------------------------------