├── .DS_Store ├── .prettierrc ├── images └── logo.png ├── .gitignore ├── services ├── misc │ ├── rave.balances.js │ ├── rave.initiate.bvn.js │ ├── rave.resolve.account.js │ ├── rave.balances-currency.js │ └── rave.verify.bvn.js ├── payment-plans │ ├── rave.retrieve.all.js │ ├── rave.create.js │ ├── rave.retrieve.single.js │ ├── rave.cancel.js │ └── rave.update.js ├── transfers │ ├── rave.retrieve.transfers.js │ ├── rave.initiate.js │ ├── rave.wallet.js │ ├── rave.bulk.js │ ├── rave.fetch.js │ └── rave.fee.js ├── virtual-cards │ ├── rave.retrieve.all.cards.js │ ├── rave.create.card.js │ ├── rave.fund.js │ ├── rave.withdraw.js │ ├── rave.retrieve.single.card.js │ ├── rave.terminate.js │ ├── rave.transactions.js │ └── rave.block_unblock.js ├── subaccount │ ├── rave.fetch.all.js │ ├── rave.create.js │ ├── rave.fetch.js │ ├── rave.delete.js │ └── rave.update.js ├── settlements │ ├── rave.retrieve-all.js │ └── rave.retrieve.js ├── transactions │ ├── rave.retrieve.js │ ├── rave.refund.js │ ├── rave.resend-hooks.js │ ├── rave.verify.js │ ├── rave.events.js │ ├── rave.fee.js │ └── rave.verify-by-txref.js ├── bills │ ├── rave.get.bill-categories.js │ ├── rave.get.bill-payment-agencies.js │ ├── rave.get.recurrings-bills.js │ ├── rave.create-bill.payment.js │ ├── rave.create-bulk.bills.js │ ├── rave.get.status.js │ ├── rave.get-bill-payments.js │ ├── rave.update-bills.order.js │ ├── rave.amount.to-be-paid.js │ ├── rave.create-order-billing-code.js │ ├── rave.products-under-an-agency.js │ └── rave.validate-bill.js ├── subscriptions │ ├── rave.retrieve.all.js │ ├── rave.retrieve.single.js │ ├── rave.cancel.js │ └── rave.activate.js ├── beneficiaries │ ├── rave.retrieve.js │ ├── rave.create.js │ ├── rave.delete.js │ └── rave.single.retrieve.js ├── ebills │ ├── rave.order.js │ └── rave.update.js ├── otps │ ├── rave.create.js │ └── rave.validate.js ├── charge │ ├── encryp.js │ ├── rave.validate.js │ ├── rave.ng-banks.js │ ├── rave.ussd.js │ ├── rave.ach.js │ ├── rave.applepay.js │ ├── rave.googlepay.js │ ├── rave.enaira.js │ ├── rave.fawrypay.js │ ├── rave.uk-banks.js │ ├── rave.bank.transfer.js │ ├── rave.card.charge.js │ └── rave.voucher.js ├── tokenized-charges │ ├── rave.charge.js │ ├── rave.bulk.charge.js │ ├── rave.update.tokens.js │ ├── rave.retrieve.a.bulk.js │ └── rave.retrieve.charge.transactions.js ├── mobile-money │ ├── rave.mpesa.js │ ├── rave.ghana.js │ ├── rave.rwanda.js │ ├── rave.uganda.js │ ├── rave.zambia.js │ ├── rave.francophone.js │ └── rave.tanzania.js ├── virtual-account │ ├── rave.create.js │ ├── rave.create.bulk.js │ ├── rave.retrieve.js │ └── rave.retrieve.bulk.js ├── banks │ ├── rave.banks-country.js │ └── rave.banks-branches.js ├── rave.custom.request.js └── schema │ ├── base.js │ ├── bill.js │ └── auxillary.js ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── bug_report.md └── workflows │ ├── security-scan.yml │ ├── change-review.yml │ └── package-publish.yml ├── lib ├── rave.custom.js ├── rave.ebills.js ├── rave.banks.js ├── rave.otps.js ├── rave.settlements.js ├── rave.beneficiaries.js ├── rave.subscriptions.js ├── rave.virtual_account.js ├── rave.misc.js ├── rave.subaccount.js ├── rave.payment_plan.js ├── rave.transfers.js ├── rave.tokenized.js ├── rave.mobile_money.js ├── rave.transactions.js ├── rave.virtual_cards.js ├── rave.charge.js ├── security.js ├── rave.bills.js └── rave.base.js ├── utils ├── validator.js ├── rave.utils.js ├── error.js ├── logger.js └── build.js ├── LICENSE ├── package.json ├── test ├── rave.subscriptions.test.js ├── rave.cards.test.js ├── rave.ebills.test.js ├── rave.otp.test.js ├── rave.bank.test.js ├── rave.beneficiaries.test.js ├── rave.transactions.test.js └── rave.misc.test.js ├── index.js ├── views └── index.pug ├── documentation ├── ebills.md ├── otp.md ├── subscription.md ├── misc.md ├── beneficiary.md ├── virtualAccount.md └── payment-plan.md ├── CONTRIBUTING.md ├── README.md └── CHANGELOG.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flutterwave/Node-v3/HEAD/.DS_Store -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flutterwave/Node-v3/HEAD/images/logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .vscode 4 | .env 5 | .prettierrc.json 6 | .eslintrc.json -------------------------------------------------------------------------------- /services/misc/rave.balances.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch(data, `Fetch all balances`, `/v3/balances?`, _rave); 5 | } 6 | 7 | module.exports = service; 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Developer Support Forum 4 | url: https://forum.flutterwave.com 5 | about: If you're having general trouble with your integration, Kindly contact our support team. 6 | -------------------------------------------------------------------------------- /services/payment-plans/rave.retrieve.all.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch(data, `Fetch all plans`, `v3/payment-plans?`, _rave); 5 | } 6 | 7 | module.exports = service; 8 | -------------------------------------------------------------------------------- /services/transfers/rave.retrieve.transfers.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch(data, `Fetch all transfers`, `/v3/transfers?`, _rave); 5 | } 6 | 7 | module.exports = service; 8 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.retrieve.all.cards.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch(data, `Fetch all cards`, `/v3/virtual-cards?`, _rave); 5 | } 6 | module.exports = service; 7 | -------------------------------------------------------------------------------- /lib/rave.custom.js: -------------------------------------------------------------------------------- 1 | // var customRequest = require('../services/rave.custom.request'); 2 | 3 | // function Custom(RaveBase) { 4 | 5 | // this.custom = function (path, data) { 6 | 7 | // return customRequest(path, data, RaveBase); 8 | // } 9 | // } 10 | 11 | // module.exports = Custom; 12 | -------------------------------------------------------------------------------- /services/subaccount/rave.fetch.all.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch all subaccount`, 7 | `/v3/subaccounts?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/settlements/rave.retrieve-all.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch all settlements`, 7 | `v3/settlements?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/transactions/rave.retrieve.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch all transactions`, 7 | `/v3/transactions?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/bills/rave.get.bill-categories.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch bill categories`, 7 | `v3/bill-categories?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/bills/rave.get.bill-payment-agencies.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch bill payment agencies`, 7 | `v3/billers?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/subscriptions/rave.retrieve.all.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch all subscriptions`, 7 | `/v3/subscriptions?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/beneficiaries/rave.retrieve.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch all transfer beneficiaries`, 7 | `/v3/beneficiaries?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/bills/rave.get.recurrings-bills.js: -------------------------------------------------------------------------------- 1 | const { handleEmptyFetch } = require('../../utils/build'); 2 | 3 | async function service(data, _rave) { 4 | return handleEmptyFetch( 5 | data, 6 | `Fetch recurring bill payments`, 7 | `v3/recurring-bills?`, 8 | _rave, 9 | ); 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /utils/validator.js: -------------------------------------------------------------------------------- 1 | const joi = require('joi'); 2 | const { validationError } = require('./error'); 3 | 4 | exports.validator = (schema, data) => { 5 | const validation = schema.validate(data); 6 | const { _, error } = validation; 7 | 8 | if (error) { 9 | const message = error.details.map((x) => x.message); 10 | throw new validationError(message); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /lib/rave.ebills.js: -------------------------------------------------------------------------------- 1 | const order_ebills = require('../services/ebills/rave.order') 2 | const update_ebills = require('../services/ebills/rave.update') 3 | 4 | function Ebills(RaveBase) { 5 | 6 | this.order = function (data) { 7 | 8 | return order_ebills(data, RaveBase); 9 | 10 | } 11 | 12 | this.update = function (data) { 13 | 14 | return update_ebills(data, RaveBase); 15 | } 16 | 17 | } 18 | module.exports = Ebills; -------------------------------------------------------------------------------- /utils/rave.utils.js: -------------------------------------------------------------------------------- 1 | var RaveUtils = {}; 2 | 3 | 4 | RaveUtils.emptyCheck = function (value, message, error) { 5 | message = message || 'Some error occured'; 6 | error = error || Error; 7 | if (!value || typeof value == 'undefined') 8 | throw new error(message); 9 | } 10 | 11 | RaveUtils.initDefaultValue = function (value, default_value) { 12 | return value || default_value; 13 | } 14 | 15 | 16 | module.exports = RaveUtils; -------------------------------------------------------------------------------- /lib/rave.banks.js: -------------------------------------------------------------------------------- 1 | const banks_branches = require('../services/banks/rave.banks-branches') 2 | const banks_country = require('../services/banks/rave.banks-country') 3 | 4 | function Bank(RaveBase) { 5 | 6 | this.branches = function (data) { 7 | 8 | return banks_branches(data, RaveBase); 9 | } 10 | 11 | this.country = function (data) { 12 | 13 | return banks_country(data, RaveBase); 14 | 15 | } 16 | } 17 | module.exports = Bank; -------------------------------------------------------------------------------- /lib/rave.otps.js: -------------------------------------------------------------------------------- 1 | const create_otp = require('../services/otps/rave.create') 2 | const validate_otp = require('../services/otps/rave.validate') 3 | 4 | 5 | function Otp(RaveBase) { 6 | 7 | this.create = function (data) { 8 | 9 | return create_otp(data, RaveBase); 10 | 11 | } 12 | 13 | this.validate = function (data) { 14 | 15 | return validate_otp(data, RaveBase); 16 | 17 | } 18 | 19 | 20 | 21 | } 22 | module.exports = Otp; -------------------------------------------------------------------------------- /services/ebills/rave.order.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { orderSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(orderSchema, data); 7 | const { body: response } = await _rave.request(`v3/ebills`, data); 8 | // logger(`Create an ebill`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/otps/rave.create.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { createOTPSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(createOTPSchema, data); 7 | const { body: response } = await _rave.request(`v3/otps`, data); 8 | // logger(`Create OTP`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/charge/encryp.js: -------------------------------------------------------------------------------- 1 | var forge = require("node-forge"); 2 | function encrypt(key, text) { 3 | var cipher = forge.cipher.createCipher( 4 | "3DES-ECB", 5 | forge.util.createBuffer(key) 6 | ); 7 | cipher.start({ 8 | iv: "" 9 | }); 10 | cipher.update(forge.util.createBuffer(text, "utf-8")); 11 | cipher.finish(); 12 | var encrypted = cipher.output; 13 | return forge.util.encode64(encrypted.getBytes()); 14 | } 15 | 16 | module.exports = encrypt -------------------------------------------------------------------------------- /lib/rave.settlements.js: -------------------------------------------------------------------------------- 1 | const retrieve_all = require('../services/settlements/rave.retrieve-all') 2 | const retrieve = require('../services/settlements/rave.retrieve') 3 | 4 | 5 | function Settlements(RaveBase) { 6 | 7 | 8 | this.fetch_all = function (data) { 9 | 10 | return retrieve_all(data, RaveBase); 11 | 12 | } 13 | 14 | this.fetch = function (data) { 15 | 16 | return retrieve(data, RaveBase); 17 | 18 | } 19 | 20 | 21 | } 22 | module.exports = Settlements; -------------------------------------------------------------------------------- /services/bills/rave.create-bill.payment.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { createSchema } = require('../schema/bill'); 4 | 5 | async function service(data, _rave) { 6 | validator(createSchema, data); 7 | const { body: response } = await _rave.request(`v3/bills`, data); 8 | // logger(`Create bill payments`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/charge/rave.validate.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { validateSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(validateSchema, data); 7 | const { body: response } = await _rave.request(`v3/validate-charge`, data); 8 | // logger(`Validate payment`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/payment-plans/rave.create.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { planSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(planSchema, data); 7 | const { body: response } = await _rave.request(`v3/payment-plans`, data); 8 | // logger(`Create a payment plan`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.create.card.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { cardSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(cardSchema, data); 7 | const { body: response } = await _rave.request(`v3/virtual-cards`, data); 8 | // logger(`Create virtual cards`, _rave); 9 | return response; 10 | } 11 | module.exports = service; 12 | -------------------------------------------------------------------------------- /services/charge/rave.ng-banks.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { bankChargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(bankChargeSchema, data); 7 | const { body: response } = await _rave.request(`v3/charges?type=mono`, data); 8 | // logger(`NG direct debit`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/charge/rave.ussd.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { ussdChargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(ussdChargeSchema, data); 7 | const { body: response } = await _rave.request(`v3/charges?type=ussd`, data); 8 | // logger(`Create USSD charge`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/subaccount/rave.create.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { subaccountSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(subaccountSchema, data); 7 | const { body: response } = await _rave.request(`v3/subaccounts`, data); 8 | // logger(`Create a subaccount`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/beneficiaries/rave.create.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { beneficiarySchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(beneficiarySchema, data); 7 | const { body: response } = await _rave.request(`v3/beneficiaries`, data); 8 | // logger(`Create beneficiary`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/bills/rave.create-bulk.bills.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { bulkCreateSchema } = require('../schema/bill'); 4 | 5 | async function service(data, _rave) { 6 | validator(bulkCreateSchema, data); 7 | const { body: response } = await _rave.request(`v3/bulk-bills`, data); 8 | // logger(`Create bulk bill payments`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/tokenized-charges/rave.charge.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { tokenSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(tokenSchema, data); 7 | const { body: response } = await _rave.request(`v3/tokenized-charges`, data); 8 | // logger(`Create tokenized payments`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/misc/rave.initiate.bvn.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { initiateBVNSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(initiateBVNSchema, data); 7 | const { body: response } = await _rave.request(`v3/bvn/verifications`, data); 8 | // logger(`Initiate BVN consent`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/mobile-money/rave.mpesa.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { momoSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(momoSchema, data); 7 | const { body: response } = await _rave.request(`v3/charges?type=mpesa`, data); 8 | // logger(`Create ${data.currency} MoMo charge`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/transfers/rave.initiate.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { transferSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(transferSchema, data); 7 | const { body: response } = await _rave.request(`v3/transfers`, data); 8 | // logger(`Initiate ${data.currency} transfers`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/transfers/rave.wallet.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { walletTransferSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(walletTransferSchema, data); 7 | const { body: response } = await _rave.request(`v3/transfers`, data); 8 | // logger(`Initiate interwallet transfers`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/charge/rave.ach.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { chargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(chargeSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=ach_payment`, 9 | data, 10 | ); 11 | // logger(`Create ACH charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/subscriptions/rave.retrieve.single.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { listSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(listSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request(`v3/subscriptions?`, data); 9 | // logger(`Fetch a subscription`, _rave); 10 | return response; 11 | } 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /utils/error.js: -------------------------------------------------------------------------------- 1 | const { errorLog } = require('./logger'); 2 | 3 | class validationError extends Error { 4 | constructor(message) { 5 | super(message); 6 | this.name = this.constructor.name; 7 | Error.captureStackTrace(this, this.constructor); 8 | } 9 | } 10 | 11 | const getErrorMessage = (err) => { 12 | if (err instanceof validationError) { 13 | return err.message; 14 | } else { 15 | errorLog.error(err.message, err); 16 | } 17 | }; 18 | 19 | module.exports = { validationError }; 20 | -------------------------------------------------------------------------------- /services/charge/rave.applepay.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { chargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(chargeSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=applepay`, 9 | data, 10 | ); 11 | // logger(`Create ApplePay charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/charge/rave.googlepay.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { chargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(chargeSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=googlepay`, 9 | data, 10 | ); 11 | // logger(`Create GooglePay charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/charge/rave.enaira.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { eNairaChargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(eNairaChargeSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=enaira`, 9 | data, 10 | ); 11 | // logger(`Create eNaira charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/charge/rave.fawrypay.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { bankChargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(bankChargeSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=fawry_pay`, 9 | data, 10 | ); 11 | // logger(`Create FawryPay charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/charge/rave.uk-banks.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { bankChargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(bankChargeSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=account-ach-uk`, 9 | data, 10 | ); 11 | // logger(`UK direct debit`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/otps/rave.validate.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { validateSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(validateSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/otps/${data.reference}/validate`, 9 | data, 10 | ); 11 | // logger(`Validate OTP`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.fund.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fundSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(fundSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/virtual-cards/${data.id}/fund`, 9 | data, 10 | ); 11 | // logger(`Fund a virtual card`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/misc/rave.resolve.account.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { resolveSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(resolveSchema, data); 7 | data.method = 'POST'; 8 | const { body: response } = await _rave.request(`v3/accounts/resolve`, data); 9 | // logger(`Resolve bank account details`, _rave); 10 | return response; 11 | } 12 | 13 | module.exports = service; 14 | -------------------------------------------------------------------------------- /services/virtual-account/rave.create.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { accountSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(accountSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/virtual-account-numbers`, 9 | data, 10 | ); 11 | // logger(`Create a virtual account`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/charge/rave.bank.transfer.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { chargeSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(chargeSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=bank_transfer`, 9 | data, 10 | ); 11 | // logger(`Create Bank transfer charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/transfers/rave.bulk.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { createBulkTransferSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(createBulkTransferSchema, data); 7 | const { body: response } = await _rave.request(`v3/bulk-transfers`, data); 8 | // logger(`Initiate bulk ${data.bulk_data.currency} transfers`, _rave); 9 | return response; 10 | } 11 | 12 | module.exports = service; 13 | -------------------------------------------------------------------------------- /services/mobile-money/rave.ghana.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { momoSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(momoSchema, data); 7 | const { body: response } = await _rave.request( 8 | `/v3/charges?type=mobile_money_ghana`, 9 | data, 10 | ); 11 | // logger(`Create ${data.currency} MoMo charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/mobile-money/rave.rwanda.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { momoSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(momoSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=mobile_money_rwanda`, 9 | data, 10 | ); 11 | // logger(`Create ${data.currency} MoMo charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/mobile-money/rave.uganda.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { momoSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(momoSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=mobile_money_uganda`, 9 | data, 10 | ); 11 | // logger(`Create ${data.currency} MoMo charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/mobile-money/rave.zambia.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { momoSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(momoSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=mobile_money_zambia`, 9 | data, 10 | ); 11 | // logger(`Create ${data.currency} MoMo charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/subaccount/rave.fetch.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `/v3/subaccounts/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Fetch a subaccount`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/mobile-money/rave.francophone.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { momoSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(momoSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=mobile_money_franco`, 9 | data, 10 | ); 11 | // logger(`Create ${data.currency} MoMo charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/mobile-money/rave.tanzania.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { momoSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(momoSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/charges?type=mobile_money_tanzania`, 9 | data, 10 | ); 11 | // logger(`Create ${data.currency} MoMo charge`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/settlements/rave.retrieve.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { listSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(listSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `/v3/settlements/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Fetch a settlement`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/subaccount/rave.delete.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'DELETE'; 8 | const { body: response } = await _rave.request( 9 | `/v3/subaccounts/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Delete a subaccount`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/subaccount/rave.update.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { listSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(listSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `/v3/subaccounts/${data.id}`, 10 | data, 11 | ); 12 | // logger(`update subaccount details`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/tokenized-charges/rave.bulk.charge.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { bulkTokenSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(bulkTokenSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/bulk-tokenized-charges`, 9 | data, 10 | ); 11 | // logger(`Create bulk tokenized payments`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/virtual-account/rave.create.bulk.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { bulkAccountSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(bulkAccountSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/bulk-virtual-account-numbers`, 9 | data, 10 | ); 11 | // logger(`Create bulk accounts`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/beneficiaries/rave.delete.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `/v3/beneficiaries/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Delete a beneficiary`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/bills/rave.get.status.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchStatusSchema } = require('../schema/bill'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchStatusSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `v3/bills/${data.reference}`, 10 | data, 11 | ); 12 | // logger(`Fetch bill status`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/ebills/rave.update.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { updateSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(updateSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `v3/ebills/${data.reference}`, 10 | data, 11 | ); 12 | // logger(`Update ebills details`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/payment-plans/rave.retrieve.single.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `/v3/payment-plans/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Fetch a plan`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.withdraw.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { withdrawalSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(withdrawalSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/virtual-cards/${data.id}/withdraw`, 9 | data, 10 | ); 11 | // logger(`Virtual card withdrawals`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/payment-plans/rave.cancel.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `v3/payment-plans/${data.id}/cancel`, 10 | data, 11 | ); 12 | // logger(`Cancel a payment plan`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/subscriptions/rave.cancel.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `v3/subscriptions/${data.id}/cancel`, 10 | data, 11 | ); 12 | // logger(`Cancel a subscription`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/transactions/rave.refund.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { refundSchema } = require('../schema/create'); 4 | 5 | async function service(data, _rave) { 6 | validator(refundSchema, data); 7 | data.method = 'POST'; 8 | const { body: response } = await _rave.request( 9 | `v3/transactions/${data.id}/refund`, 10 | data, 11 | ); 12 | // logger(`Initiate a refund`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/bills/rave.get-bill-payments.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { listSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(listSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `v3/bills?from=${data.from}&to=${data.to}`, 10 | data, 11 | ); 12 | // logger(`Fetch bill payments`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/payment-plans/rave.update.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { updatePlanSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(updatePlanSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `v3/payment-plans/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Update plan details`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/subscriptions/rave.activate.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `v3/subscriptions/${data.id}/activate`, 10 | data, 11 | ); 12 | // logger(`Activate a subscription`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/beneficiaries/rave.single.retrieve.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `/v3/beneficiaries/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Fetch a transfer beneficiary`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/transactions/rave.resend-hooks.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'POST'; 8 | const { body: response } = await _rave.request( 9 | `v3/transactions/${data.id}/resend-hook`, 10 | data, 11 | ); 12 | // logger(`Resend failed webhooks`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.retrieve.single.card.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `/v3/virtual-cards/${data.id}`, 10 | data, 11 | ); 12 | // logger(`Fetch a virtual card`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.terminate.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `/v3/virtual-cards/${data.id}/terminate`, 10 | data, 11 | ); 12 | // logger(`Delete a virtual card`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/bills/rave.update-bills.order.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { updateOrderSchema } = require('../schema/bill'); 4 | 5 | async function service(data, _rave) { 6 | validator(updateOrderSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `v3/product-orders/${data.reference}`, 10 | data, 11 | ); 12 | // logger(`Update bill order`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/tokenized-charges/rave.update.tokens.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { updateTokenSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(updateTokenSchema, data); 7 | data.method = 'PUT'; 8 | const { body: response } = await _rave.request( 9 | `v3/tokens/${data.token}`, 10 | data, 11 | ); 12 | // logger(`Update card token`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/transfers/rave.fetch.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `/v3/transfers/${data.id}`, 11 | data, 12 | ); 13 | // logger(`Fetch a transfer`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.transactions.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { listSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(listSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `v3/virtual-cards/${data.id}/transactions?`, 10 | data, 11 | ); 12 | // logger(`Fetch card transactions`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/banks/rave.banks-country.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { listSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(listSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/banks/${data.country}`, 11 | data, 12 | ); 13 | // logger(`Get banks by country`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/banks/rave.banks-branches.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/banks/${data.id}/branches`, 11 | data, 12 | ); 13 | // logger(`Get bank branches`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/bills/rave.amount.to-be-paid.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { amountQuerySchema } = require('../schema/bill'); 4 | 5 | async function service(data, _rave) { 6 | validator(amountQuerySchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `v3/billers/${data.id}/products/${data.product_id}`, 10 | data, 11 | ); 12 | // logger(`Fetch bill amount`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/bills/rave.create-order-billing-code.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { createOrderSchema } = require('../schema/bill'); 4 | 5 | async function service(data, _rave) { 6 | validator(createOrderSchema, data); 7 | const { body: response } = await _rave.request( 8 | `v3/billers/${data.id}/products/${data.product_id}/orders`, 9 | data, 10 | ); 11 | // logger(`Create order with billing code`, _rave); 12 | return response; 13 | } 14 | 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/tokenized-charges/rave.retrieve.a.bulk.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { retrieveSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(retrieveSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `v3/bulk-tokenized-charges/${data.bulk_id}`, 10 | data, 11 | ); 12 | // logger(`Bulk tokenized status`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/transactions/rave.verify.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/transactions/${data.id}/verify`, 11 | data, 12 | ); 13 | // logger(`Verify Transactions`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/transactions/rave.events.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `/v3/transactions/${data.id}/events`, 11 | data, 12 | ); 13 | // logger(`View transaction events`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/misc/rave.balances-currency.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchBalance } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchBalance, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `/v3/balances/${data.currency}`, 11 | data, 12 | ); 13 | // logger(`Query balance by currency`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/virtual-account/rave.retrieve.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchAccountSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchAccountSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `v3/bulk-virtual-account-numbers/${data.order_ref}`, 10 | data, 11 | ); 12 | // logger(`Fetch account details`, _rave); 13 | return response; 14 | } 15 | 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/bills/rave.products-under-an-agency.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchSchema } = require('../schema/base'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/billers/${data.id}/products`, 11 | data, 12 | ); 13 | // logger(`Retrieve bills by agency`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/misc/rave.verify.bvn.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { verifyBVNSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(verifyBVNSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/bvn/verifications/${data.reference}`, 11 | data, 12 | ); 13 | // logger(`Verify BVN consent`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/transactions/rave.fee.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { feeSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(feeSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/transactions/fee?amount=${data.amount}¤cy=${data.currency}`, 11 | data, 12 | ); 13 | // logger(`Create OTP`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/tokenized-charges/rave.retrieve.charge.transactions.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { retrieveSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(retrieveSchema, data); 7 | data.method = 'GET'; 8 | const { body: response } = await _rave.request( 9 | `v3/bulk-tokenized-charges/${data.bulk_id}/transactions`, 10 | data, 11 | ); 12 | // logger(`Fetch bulk tokenized payments`, _rave); 13 | return response; 14 | } 15 | module.exports = service; 16 | -------------------------------------------------------------------------------- /services/transactions/rave.verify-by-txref.js: -------------------------------------------------------------------------------- 1 | const { listSchema } = require('../schema/base'); 2 | // const { logger } = require('../../utils/logger'); 3 | const { validator } = require('../../utils/validator'); 4 | 5 | async function service(data, _rave) { 6 | validator(listSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/transactions/verify_by_reference?tx_ref=${data.tx_ref}`, 11 | data, 12 | ); 13 | // logger(`Verify Transactions by tx_ref`, _rave); 14 | return response; 15 | } 16 | module.exports = service; 17 | -------------------------------------------------------------------------------- /services/bills/rave.validate-bill.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { validateSchema } = require('../schema/bill'); 4 | 5 | async function service(data, _rave) { 6 | validator(validateSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/bill-items/${data.item_code}/validate?code=${data.code}&customer=${data.customer}`, 11 | data, 12 | ); 13 | // logger(`Validate bill payment`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/virtual-account/rave.retrieve.bulk.js: -------------------------------------------------------------------------------- 1 | // const { logger } = require('../../utils/logger'); 2 | const { validator } = require('../../utils/validator'); 3 | const { fetchBulkAccountSchema } = require('../schema/auxillary'); 4 | 5 | async function service(data, _rave) { 6 | validator(fetchBulkAccountSchema, data); 7 | data.method = 'GET'; 8 | data.excludeQuery = true; 9 | const { body: response } = await _rave.request( 10 | `v3/bulk-virtual-account-numbers/${data.batch_id}`, 11 | data, 12 | ); 13 | // logger(`Fetch bulk account details`, _rave); 14 | return response; 15 | } 16 | 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/transfers/rave.fee.js: -------------------------------------------------------------------------------- 1 | const { listSchema } = require('../schema/base'); 2 | // const { logger } = require('../../utils/logger'); 3 | const { validator } = require('../../utils/validator'); 4 | // const enforceRequired = require('../../utils/build'); 5 | 6 | async function service(data, _rave) { 7 | validator(listSchema, data); 8 | data.method = 'GET'; 9 | data.excludeQuery = true; 10 | const { body: response } = await _rave.request( 11 | `v3/transfers/fee?currency=${data.currency}&amount=${data.amount}`, 12 | data, 13 | ); 14 | // logger(`Fetch transfer fees`, _rave); 15 | return response; 16 | } 17 | module.exports = service; 18 | -------------------------------------------------------------------------------- /services/rave.custom.request.js: -------------------------------------------------------------------------------- 1 | // var morx = require('morx'); 2 | 3 | // var q = require('q'); 4 | 5 | // function newRefund(path, data, _rave) { 6 | // var d = q.defer(); 7 | 8 | // q.fcall(() => { 9 | // path = path || 'NO PATH PASSED, PLEASE PASS A VALID PATH'; 10 | 11 | // if (path == 'NO PATH PASSED, PLEASE PASS A VALID PATH') { 12 | // throw path; 13 | // } 14 | 15 | // return _rave.request(path, data); 16 | // }) 17 | // .then((response) => { 18 | // d.resolve(response); 19 | // }) 20 | // .catch((err) => { 21 | // d.reject(err); 22 | // }); 23 | 24 | // return d.promise; 25 | // } 26 | 27 | // module.exports = newRefund; 28 | -------------------------------------------------------------------------------- /services/virtual-cards/rave.block_unblock.js: -------------------------------------------------------------------------------- 1 | const joi = require('joi'); 2 | // const { logger } = require('../../utils/logger'); 3 | const { validator } = require('../../utils/validator'); 4 | 5 | const spec = joi.object({ 6 | id: joi.string().required(), 7 | status_action: joi.string().valid('block', 'unblock').required(), 8 | }); 9 | 10 | async function service(data, _rave) { 11 | validator(spec, data); 12 | data.method = 'PUT'; 13 | const { body: response } = await _rave.request( 14 | `v3/virtual-cards/${data.id}/status/${data.status_action}`, 15 | data, 16 | ); 17 | // logger(`Fund a virtual card`, _rave); 18 | return response; 19 | } 20 | module.exports = service; 21 | -------------------------------------------------------------------------------- /services/charge/rave.card.charge.js: -------------------------------------------------------------------------------- 1 | const encrypt = require('./encryp'); 2 | // const { logger } = require('../../utils/logger'); 3 | const { validator } = require('../../utils/validator'); 4 | const { cardChargeSchema } = require('../schema/create'); 5 | 6 | async function service(data, _rave) { 7 | validator(cardChargeSchema, data); 8 | 9 | var encrypted = encrypt(data.enckey, JSON.stringify(data)); 10 | var payload = {}; 11 | payload.public_key = _rave.getPublicKey(); 12 | payload.client = encrypted; 13 | 14 | const { body: response } = await _rave.request( 15 | `v3/charges?type=card`, 16 | payload, 17 | ); 18 | 19 | // logger(`Create card charge`, _rave); 20 | return response; 21 | } 22 | module.exports = service; 23 | -------------------------------------------------------------------------------- /lib/rave.beneficiaries.js: -------------------------------------------------------------------------------- 1 | const create_beneficiary = require('../services/beneficiaries/rave.create'); 2 | const del_beneficiary = require('../services/beneficiaries/rave.delete'); 3 | const retrieve_all = require('../services/beneficiaries/rave.retrieve'); 4 | const retrieve = require('../services/beneficiaries/rave.single.retrieve'); 5 | 6 | function Beneficiaries(RaveBase) { 7 | this.create = function (data) { 8 | return create_beneficiary(data, RaveBase); 9 | }; 10 | 11 | this.delete = function (data) { 12 | return del_beneficiary(data, RaveBase); 13 | }; 14 | this.fetch_all = function (data) { 15 | return retrieve_all(data, RaveBase); 16 | }; 17 | this.fetch = function (data) { 18 | return retrieve(data, RaveBase); 19 | }; 20 | } 21 | module.exports = Beneficiaries; 22 | -------------------------------------------------------------------------------- /lib/rave.subscriptions.js: -------------------------------------------------------------------------------- 1 | const activate_sub = require('../services/subscriptions/rave.activate') 2 | const cancel_sub = require('../services/subscriptions/rave.cancel') 3 | const retrieve_all = require('../services/subscriptions/rave.retrieve.all') 4 | const fetch_one = require('../services/subscriptions/rave.retrieve.single') 5 | 6 | 7 | function Subscriptions(RaveBase) { 8 | 9 | 10 | this.activate = function (data) { 11 | 12 | return activate_sub(data, RaveBase); 13 | 14 | } 15 | 16 | this.cancel = function (data) { 17 | 18 | return cancel_sub(data, RaveBase); 19 | 20 | } 21 | 22 | this.fetch_all = function (data) { 23 | 24 | return retrieve_all(data, RaveBase); 25 | 26 | } 27 | 28 | this.get = function (data) { 29 | 30 | return fetch_one(data, RaveBase); 31 | 32 | } 33 | 34 | } 35 | module.exports = Subscriptions; -------------------------------------------------------------------------------- /.github/workflows/security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Security scan on all changes (Commits/PRs) 2 | 3 | on: 4 | push: 5 | branches: ['main', 'master', 'pilots', 'dev'] 6 | pull_request: 7 | types: 8 | - opened 9 | 10 | jobs: 11 | code-check: 12 | runs-on: ubuntu-latest 13 | env: 14 | OS: ubuntu-latest 15 | steps: 16 | - name: checkout code 17 | uses: actions/checkout@v2 18 | 19 | - name: Checkmarx One ClI Action 20 | uses: checkmarx/ast-github-action@main 21 | with: 22 | project_name: Node-v3 23 | cx_tenant: Flutterwave 24 | base_uri: https://eu.ast.checkmarx.net/ 25 | cx_client_id: ${{ secrets.CX_CLIENT_ID }} 26 | cx_client_secret: ${{ secrets.CX_CLIENT_SECRET }} 27 | additional_params: --scan-types sast,iac-security,api-security,sca,container-security 28 | -------------------------------------------------------------------------------- /lib/rave.virtual_account.js: -------------------------------------------------------------------------------- 1 | const create_bulk_account = require('../services/virtual-account/rave.create.bulk') 2 | const initiate = require('../services/virtual-account/rave.create') 3 | const retrieve = require('../services/virtual-account/rave.retrieve') 4 | const retrieve_bulk = require('../services/virtual-account/rave.retrieve.bulk') 5 | 6 | 7 | 8 | function Virtual_account(RaveBase) { 9 | 10 | 11 | this.create_bulk = function (data) { 12 | 13 | return create_bulk_account(data, RaveBase); 14 | 15 | } 16 | this.create = function (data) { 17 | 18 | return initiate(data, RaveBase); 19 | 20 | } 21 | 22 | this.fetch = function (data) { 23 | 24 | return retrieve(data, RaveBase); 25 | 26 | } 27 | 28 | this.fetch_bulk = function (data) { 29 | 30 | return retrieve_bulk(data, RaveBase); 31 | 32 | } 33 | 34 | 35 | 36 | } 37 | module.exports = Virtual_account; -------------------------------------------------------------------------------- /lib/rave.misc.js: -------------------------------------------------------------------------------- 1 | const balances_currency = require('../services/misc/rave.balances-currency'); 2 | const get_bal = require('../services/misc/rave.balances'); 3 | const initBVN = require('../services/misc/rave.initiate.bvn'); 4 | const verifBVN = require('../services/misc/rave.verify.bvn') 5 | const resolve_act = require('../services/misc/rave.resolve.account'); 6 | 7 | function Misc(RaveBase) { 8 | this.bal_currency = function (data) { 9 | return balances_currency(data, RaveBase); 10 | }; 11 | 12 | this.bal = function (data) { 13 | return get_bal(data, RaveBase); 14 | }; 15 | 16 | this.bvn = function (data) { 17 | return initBVN(data, RaveBase); 18 | }; 19 | 20 | this.verifybvn = function (data) { 21 | return verifBVN(data, RaveBase); 22 | } 23 | 24 | this.verify_Account = function (data) { 25 | return resolve_act(data, RaveBase); 26 | }; 27 | } 28 | module.exports = Misc; 29 | -------------------------------------------------------------------------------- /lib/rave.subaccount.js: -------------------------------------------------------------------------------- 1 | const create_sub = require('../services/subaccount/rave.create') 2 | const del_sub = require('../services/subaccount/rave.delete') 3 | const get_all = require('../services/subaccount/rave.fetch.all') 4 | const get = require('../services/subaccount/rave.fetch') 5 | const update_sub = require('../services/subaccount/rave.update') 6 | 7 | function Subaccount(RaveBase) { 8 | 9 | 10 | this.create = function (data) { 11 | 12 | return create_sub(data, RaveBase); 13 | 14 | } 15 | 16 | this.delete = function (data) { 17 | 18 | return del_sub(data, RaveBase); 19 | 20 | } 21 | 22 | this.fetch_all = function (data) { 23 | 24 | return get_all(data, RaveBase); 25 | 26 | } 27 | 28 | this.fetch = function (data) { 29 | 30 | return get(data, RaveBase); 31 | 32 | } 33 | 34 | this.update = function (data) { 35 | 36 | return update_sub(data, RaveBase); 37 | 38 | } 39 | 40 | 41 | 42 | } 43 | module.exports = Subaccount; -------------------------------------------------------------------------------- /utils/logger.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const packageJson = require('../package.json'); 3 | const { createLogger, format, transports } = require('winston'); 4 | const { combine, timestamp, colorize, errors, printf, json } = format; 5 | 6 | // function logger(name, _rave) { 7 | // axios.post( 8 | // 'https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/staging/sendevent', 9 | // { 10 | // publicKey: _rave.getPublicKey(), 11 | // language: 'NodeJs v3', 12 | // version: packageJson.version, 13 | // title: 'Incoming call', 14 | // message: name, 15 | // }, 16 | // ); 17 | // } 18 | 19 | const errorLogger = createLogger({ 20 | transports: [ 21 | new transports.Console({ 22 | format: combine( 23 | errors({ 24 | stack: true, 25 | }), 26 | timestamp(), 27 | json(), 28 | ), 29 | }), 30 | ], 31 | }); 32 | 33 | module.exports = { errorLog: errorLogger }; 34 | -------------------------------------------------------------------------------- /lib/rave.payment_plan.js: -------------------------------------------------------------------------------- 1 | const create_plan = require('../services/payment-plans/rave.create') 2 | const cancel_plan = require('../services/payment-plans/rave.cancel') 3 | const retrieve_all = require('../services/payment-plans/rave.retrieve.all') 4 | const retrieve_single = require('../services/payment-plans/rave.retrieve.single') 5 | const update_plan = require('../services/payment-plans/rave.update') 6 | 7 | 8 | 9 | function Payment_plan(RaveBase) { 10 | 11 | 12 | this.create = function (data) { 13 | 14 | return create_plan(data, RaveBase); 15 | 16 | } 17 | 18 | this.cancel = function (data) { 19 | 20 | return cancel_plan(data, RaveBase); 21 | 22 | } 23 | this.get_all = function (data) { 24 | 25 | return retrieve_all(data, RaveBase); 26 | 27 | } 28 | this.get_plan = function (data) { 29 | 30 | return retrieve_single(data, RaveBase); 31 | 32 | } 33 | this.update = function (data) { 34 | 35 | return update_plan(data, RaveBase); 36 | 37 | } 38 | 39 | } 40 | module.exports = Payment_plan; -------------------------------------------------------------------------------- /lib/rave.transfers.js: -------------------------------------------------------------------------------- 1 | const bulk_transfer = require('../services/transfers/rave.bulk'); 2 | const fee_transfer = require('../services/transfers/rave.fee'); 3 | const initiate_transfer = require('../services/transfers/rave.initiate'); 4 | const fetch_transfers = require('../services/transfers/rave.retrieve.transfers'); 5 | const getATransfer = require('../services/transfers/rave.fetch'); 6 | const wallet = require('../services/transfers/rave.wallet'); 7 | 8 | function Transfers(RaveBase) { 9 | this.bulk = function (data) { 10 | return bulk_transfer(data, RaveBase); 11 | }; 12 | 13 | this.fee = function (data) { 14 | return fee_transfer(data, RaveBase); 15 | }; 16 | this.initiate = function (data) { 17 | return initiate_transfer(data, RaveBase); 18 | }; 19 | this.fetch = function (data) { 20 | return fetch_transfers(data, RaveBase); 21 | }; 22 | this.get_a_transfer = function (data) { 23 | return getATransfer(data, RaveBase); 24 | }; 25 | this.wallet_to_wallet = function (data) { 26 | return wallet(data, RaveBase); 27 | }; 28 | } 29 | module.exports = Transfers; 30 | -------------------------------------------------------------------------------- /lib/rave.tokenized.js: -------------------------------------------------------------------------------- 1 | const bulk_charge = require('../services/tokenized-charges/rave.bulk.charge') 2 | const charge_token = require('../services/tokenized-charges/rave.charge') 3 | const retrieve_a_bulk = require('../services/tokenized-charges/rave.retrieve.a.bulk') 4 | const retrieve_charge_trans = require('../services/tokenized-charges/rave.retrieve.charge.transactions') 5 | const update_a_token = require('../services/tokenized-charges/rave.update.tokens') 6 | 7 | 8 | 9 | 10 | function Tokenized(RaveBase) { 11 | 12 | 13 | this.charge = function (data) { 14 | 15 | return charge_token(data, RaveBase); 16 | 17 | } 18 | this.fetch_bulk = function (data) { 19 | 20 | return retrieve_a_bulk(data, RaveBase); 21 | 22 | } 23 | 24 | this.bulk = function (data) { 25 | 26 | return bulk_charge(data, RaveBase); 27 | 28 | } 29 | 30 | this.fetch_charge_transactions = function (data) { 31 | 32 | return retrieve_charge_trans(data, RaveBase); 33 | 34 | } 35 | 36 | 37 | this.update_token = function (data) { 38 | 39 | return update_a_token(data, RaveBase); 40 | 41 | } 42 | 43 | 44 | 45 | } 46 | module.exports = Tokenized; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Flutterwave 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 | -------------------------------------------------------------------------------- /lib/rave.mobile_money.js: -------------------------------------------------------------------------------- 1 | const gh = require('../services/mobile-money/rave.ghana'); 2 | const mpesa_money = require('../services/mobile-money/rave.mpesa'); 3 | const rw = require('../services/mobile-money/rave.rwanda'); 4 | const ug = require('../services/mobile-money/rave.uganda'); 5 | const zm = require('../services/mobile-money/rave.zambia'); 6 | const franc = require('../services/mobile-money/rave.francophone'); 7 | const tz = require('../services/mobile-money/rave.tanzania') 8 | 9 | function Mobile_money(RaveBase) { 10 | this.ghana = function (data) { 11 | return gh(data, RaveBase); 12 | }; 13 | 14 | this.mpesa = function (data) { 15 | return mpesa_money(data, RaveBase); 16 | }; 17 | 18 | this.rwanda = function (data) { 19 | return rw(data, RaveBase); 20 | }; 21 | 22 | this.uganda = function (data) { 23 | return ug(data, RaveBase); 24 | }; 25 | this.franco_phone = function (data) { 26 | return franc(data, RaveBase); 27 | }; 28 | 29 | this.zambia = function (data) { 30 | return zm(data, RaveBase); 31 | }; 32 | 33 | this.tanzania = function (data) { 34 | return tz(data, RaveBase); 35 | } 36 | } 37 | module.exports = Mobile_money; 38 | -------------------------------------------------------------------------------- /lib/rave.transactions.js: -------------------------------------------------------------------------------- 1 | const event_trans = require('../services/transactions/rave.events'); 2 | const fee_trans = require('../services/transactions/rave.fee'); 3 | const refund_trans = require('../services/transactions/rave.refund'); 4 | const resend_hooks_trans = require('../services/transactions/rave.resend-hooks'); 5 | const retrieve_trans = require('../services/transactions/rave.retrieve'); 6 | const verify_trans = require('../services/transactions/rave.verify'); 7 | const verify_trans_tx = require('../services/transactions/rave.verify-by-txref'); 8 | 9 | function Transactions(RaveBase) { 10 | this.event = function (data) { 11 | return event_trans(data, RaveBase); 12 | }; 13 | 14 | this.fee = function (data) { 15 | return fee_trans(data, RaveBase); 16 | }; 17 | 18 | this.refund = function (data) { 19 | return refund_trans(data, RaveBase); 20 | }; 21 | 22 | this.resend_hooks = function (data) { 23 | return resend_hooks_trans(data, RaveBase); 24 | }; 25 | 26 | this.fetch = function (data) { 27 | return retrieve_trans(data, RaveBase); 28 | }; 29 | 30 | this.verify = function (data) { 31 | return verify_trans(data, RaveBase); 32 | }; 33 | 34 | this.verify_by_tx = function (data) { 35 | return verify_trans_tx(data, RaveBase); 36 | } 37 | } 38 | module.exports = Transactions; 39 | -------------------------------------------------------------------------------- /.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 | Have you read our [Code of Conduct](https://github.com/Flutterwave/Python/blob/master/CONTRIBUTING.md)? By filing an Issue, you are expected to comply with it, including treating everyone with respect. 11 | 12 | # Description 13 | 14 | 15 | # Steps to Reproduce 16 | 17 | 1. 18 | 2. 19 | 3. 20 | 21 | ## Expected behaviour 22 | 23 | 24 | ## Actual behaviour 25 | 26 | 27 | ## Reproduces how often 28 | 29 | 30 | # Configuration 31 | - API Version: 32 | - Environment: 33 | - Browser: 34 | - Language: 35 | 36 | # Additional Information 37 | 38 | -------------------------------------------------------------------------------- /.github/workflows/change-review.yml: -------------------------------------------------------------------------------- 1 | name: Review changes on Dev (Commits/PRs) 2 | on: 3 | push: 4 | branches: ['dev'] 5 | pull_request: 6 | types: 7 | - opened 8 | 9 | jobs: 10 | code-check: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: 18 17 | 18 | - uses: actions/checkout@v4 19 | 20 | - name: 'Cache node_modules' 21 | uses: actions/cache@v4 22 | with: 23 | path: ~/.npm 24 | key: ${{ runner.os }}-node-v18-${{ hashFiles('**/package-lock.json') }} 25 | restore-keys: | 26 | ${{ runner.os }}-node-v18- 27 | 28 | - name: Install Dependencies 29 | run: | 30 | npm install 31 | 32 | - name: run unit tests and coverage scan 33 | env: 34 | PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} 35 | SECRET_KEY: ${{ secrets.SECRET_KEY }} 36 | run: npm run coverage 37 | 38 | - name: upload coverage report to codecov 39 | uses: codecov/codecov-action@v4 40 | 41 | - name: push build status to Slack 42 | uses: 8398a7/action-slack@v3 43 | with: 44 | status: ${{ job.status }} 45 | fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest 46 | env: 47 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 48 | MATRIX_CONTEXT: ${{ toJson(matrix) }} 49 | if: always() 50 | -------------------------------------------------------------------------------- /utils/build.js: -------------------------------------------------------------------------------- 1 | const joi = require('joi'); 2 | const { listSchema } = require('../services/schema/base'); 3 | // const { logger } = require('./logger'); 4 | const { validator } = require('./validator'); 5 | 6 | // make parameter required in the listSchema 7 | function enforceRequired(schema, paramList) { 8 | if (!Array.isArray(paramList)) { 9 | throw new Error('paramList must be an array'); 10 | } 11 | // params.forEach((param) => {}); 12 | paramList.map((param) => { 13 | schema.keys({ 14 | [param]: schema._ids._byKey[param].rules.concat( 15 | joi 16 | .string() 17 | .required() 18 | .messages({ 19 | 'any.required': `${param} is required!`, 20 | }), 21 | ), 22 | }); 23 | }); 24 | return schema; 25 | } 26 | 27 | // Graciously handle fetch queries with empty payload 28 | async function handleEmptyFetch(param, name, uri, _rave) { 29 | if (param === undefined || param === null) { 30 | param = {}; 31 | param.method = 'GET'; 32 | 33 | const response = await _rave.request(uri, param); 34 | 35 | const responseBody = response.body || response; 36 | 37 | // logger(name, _rave); 38 | return responseBody; 39 | } 40 | 41 | validator(listSchema, param); 42 | param.method = 'GET'; 43 | 44 | const response = await _rave.request(uri, param); 45 | const responseBody = response.body || response; 46 | 47 | // logger(name, _rave); 48 | return responseBody; 49 | } 50 | 51 | module.exports = { enforceRequired, handleEmptyFetch }; 52 | -------------------------------------------------------------------------------- /lib/rave.virtual_cards.js: -------------------------------------------------------------------------------- 1 | const create_Card = require('../services/virtual-cards/rave.create.card'); 2 | const fund_Card = require('../services/virtual-cards/rave.fund'); 3 | const retrieve_all_Cards = require('../services/virtual-cards/rave.retrieve.all.cards'); 4 | const block_card = require('../services/virtual-cards/rave.block_unblock'); 5 | const unblock_card = require('../services/virtual-cards/rave.block_unblock'); 6 | const terminate_card = require('../services/virtual-cards/rave.terminate'); 7 | const card_transactions = require('../services/virtual-cards/rave.transactions'); 8 | const withdraw_from_Card = require('../services/virtual-cards/rave.withdraw'); 9 | const retrieve_single_Card = require('../services/virtual-cards/rave.retrieve.single.card'); 10 | 11 | function Virtual_card(RaveBase) { 12 | this.create = function (data) { 13 | return create_Card(data, RaveBase); 14 | }; 15 | this.fund = function (data) { 16 | return fund_Card(data, RaveBase); 17 | }; 18 | 19 | this.fetch_all = function (data) { 20 | return retrieve_all_Cards(data, RaveBase); 21 | }; 22 | this.fetch = function (data) { 23 | return retrieve_single_Card(data, RaveBase); 24 | }; 25 | 26 | this.block = function (data) { 27 | return block_card(data, RaveBase); 28 | }; 29 | this.unblock = function (data) { 30 | return unblock_card(data, RaveBase); 31 | }; 32 | this.terminate = function (data) { 33 | return terminate_card(data, RaveBase); 34 | }; 35 | this.transactions = function (data) { 36 | return card_transactions(data, RaveBase); 37 | }; 38 | this.withdraw_funds = function (data) { 39 | return withdraw_from_Card(data, RaveBase); 40 | }; 41 | } 42 | module.exports = Virtual_card; 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutterwave-node-v3", 3 | "version": "1.3.0", 4 | "description": "The official Node.JS library for Flutterwave v3 payment APIs", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha **/*.test.js", 8 | "test-watch": "nodemon --exec \"npm test\"", 9 | "coverage": "nyc npm run test", 10 | "report-coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov" 11 | }, 12 | "nyc": { 13 | "coverage": "test", 14 | "check-coverage": true, 15 | "functions": 5, 16 | "lines": 5, 17 | "report-dir": "./coverage", 18 | "reporter": [ 19 | "lcov" 20 | ] 21 | }, 22 | "keywords": [], 23 | "author": "Flutterwave Developers", 24 | "license": "MIT", 25 | "dependencies": { 26 | "axios": "^1.8.4", 27 | "bluebird": "^3.7.2", 28 | "chai-as-promised-also-chain": "^1.0.2", 29 | "eslint-config-prettier": "^8.6.0", 30 | "joi": "^17.8.3", 31 | "md5": "^2.3.0", 32 | "node-forge": "1.3.0", 33 | "q": "^1.5.1", 34 | "sha.js": "^2.4.11", 35 | "winston": "^3.8.2" 36 | }, 37 | "devDependencies": { 38 | "chai": "^4.3.6", 39 | "chai-as-promised": "^7.1.1", 40 | "codecov": "^3.8.3", 41 | "dotenv": "^10.0.0", 42 | "eslint": "^8.33.0", 43 | "eslint-config-airbnb-base": "^15.0.0", 44 | "eslint-plugin-import": "^2.27.5", 45 | "mocha": "^9.2.2", 46 | "nyc": "^15.1.0", 47 | "prettier": "2.8.3", 48 | "should": "^13.2.3", 49 | "sinon": "^15.0.1", 50 | "sinon-chai": "^3.7.0" 51 | }, 52 | "directories": { 53 | "lib": "lib", 54 | "test": "test" 55 | }, 56 | "repository": { 57 | "type": "git", 58 | "url": "git+https://github.com/Flutterwave/Flutterwave-node-v3.git" 59 | }, 60 | "bugs": { 61 | "url": "https://github.com/Flutterwave/Flutterwave-node-v3/issues" 62 | }, 63 | "homepage": "https://github.com/Flutterwave/Flutterwave-node-v3#readme" 64 | } 65 | -------------------------------------------------------------------------------- /lib/rave.charge.js: -------------------------------------------------------------------------------- 1 | const card_charge = require('../services/charge/rave.card.charge'); 2 | const ng_banks = require('../services/charge/rave.ng-banks'); 3 | const uk_bank = require('../services/charge/rave.uk-banks'); 4 | const ussd_Charge = require('../services/charge/rave.ussd'); 5 | const validate_charge = require('../services/charge/rave.validate'); 6 | const voucher_charge = require('../services/charge/rave.voucher'); 7 | const ach_payment = require('../services/charge/rave.ach'); 8 | const bank_trans = require('../services/charge/rave.bank.transfer'); 9 | const applepay = require('../services/charge/rave.applepay'); 10 | const googlepay = require('../services/charge/rave.googlepay'); 11 | const enaira = require('../services/charge/rave.enaira'); 12 | const fawrypay = require('../services/charge/rave.fawrypay'); 13 | 14 | function Charge(RaveBase) { 15 | this.card = function (data) { 16 | return card_charge(data, RaveBase); 17 | }; 18 | 19 | this.ng = function (data) { 20 | return ng_banks(data, RaveBase); 21 | }; 22 | 23 | this.ach = function (data) { 24 | return ach_payment(data, RaveBase); 25 | }; 26 | 27 | this.uk = function (data) { 28 | return uk_bank(data, RaveBase); 29 | }; 30 | 31 | this.ussd = function (data) { 32 | return ussd_Charge(data, RaveBase); 33 | }; 34 | 35 | this.validate = function (data) { 36 | return validate_charge(data, RaveBase); 37 | }; 38 | 39 | this.voucher = function (data) { 40 | return voucher_charge(data, RaveBase); 41 | }; 42 | this.bank_transfer = function (data) { 43 | return bank_trans(data, RaveBase); 44 | }; 45 | this.applepay = function (data) { 46 | return applepay(data, RaveBase); 47 | }; 48 | this.googlepay = function (data) { 49 | return googlepay(data, RaveBase); 50 | }; 51 | this.enaira = function (data) { 52 | return enaira(data, RaveBase); 53 | }; 54 | this.fawrypay = function (data) { 55 | return fawrypay(data, RaveBase); 56 | }; 57 | } 58 | module.exports = Charge; 59 | -------------------------------------------------------------------------------- /.github/workflows/package-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish changes to Node package manager 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | check-readme-and-changelog: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | 14 | - name: Check for README and CHANGELOG changes 15 | run: | 16 | if ! git diff --quiet HEAD~ HEAD -- README.md CHANGELOG.md; then 17 | echo "README and/or CHANGELOG have been modified. Proceeding with deployment." 18 | else 19 | echo "README and/or CHANGELOG have not been modified. Terminating deployment." 20 | exit 1 21 | fi 22 | 23 | - name: push build status to Slack 24 | uses: 8398a7/action-slack@v3 25 | with: 26 | status: ${{ job.status }} 27 | fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest 28 | env: 29 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 30 | if: always() 31 | 32 | publish: 33 | needs: check-readme-and-changelog 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Checkout code 37 | uses: actions/checkout@v2 38 | 39 | - name: Setup Node Engine 40 | uses: actions/setup-node@v1 41 | with: 42 | node-version: 16 43 | registry-url: https://registry.npmjs.org/ 44 | 45 | - name: Install Node dependencies 46 | run: npm ci 47 | 48 | - run: npm publish 49 | env: 50 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 51 | 52 | - name: Send Slack Notification 53 | uses: 8398a7/action-slack@v3 54 | with: 55 | status: ${{ job.status }} 56 | fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest 57 | env: 58 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 59 | MATRIX_CONTEXT: ${{ toJson(matrix) }} 60 | if: always() 61 | -------------------------------------------------------------------------------- /test/rave.subscriptions.test.js: -------------------------------------------------------------------------------- 1 | const Subscriptions = require('../lib/rave.subscriptions'); 2 | var base = require('../lib/rave.base'); 3 | 4 | var Promise = require('bluebird'); 5 | var mocha = require('mocha'); 6 | var chai = require('chai'); 7 | var expect = chai.expect; 8 | var chaiAsPromised = require('chai-as-promised'); 9 | 10 | var dotenv = require('dotenv').config(); 11 | 12 | const sinon = require('sinon'); 13 | const sinonChai = require('sinon-chai'); 14 | 15 | chai.use(chaiAsPromised); 16 | chai.use(sinonChai); 17 | 18 | describe('#Rave Subscriptions', function () { 19 | const public_key = process.env.PUBLIC_KEY; 20 | const secret_key = process.env.SECRET_KEY; 21 | const ravebase = new base(public_key, secret_key); 22 | 23 | let subscriptionInstance; 24 | let subscriptionStub; 25 | 26 | beforeEach(() => { 27 | subscriptionInstance = new Subscriptions(ravebase); 28 | }); 29 | 30 | afterEach(() => { 31 | sinon.restore(); 32 | }); 33 | 34 | // it.only('should return a single subscription ', async function () { 35 | // this.timeout(10000); 36 | 37 | // var payload = { 38 | // email: 'cornelius@flutterwavego.com', 39 | // }; 40 | // var resp = await subscriptionInstance.get(payload); 41 | // console.log(resp); 42 | // return expect(resp).to.have.property('data'); 43 | // }); 44 | 45 | // it("should cancel a user's subscription", async function () { 46 | // this.timeout(10000); 47 | 48 | // var payload = { 49 | // id: '11343', 50 | // }; 51 | // var resp = await subscriptionInstance.cancel(payload); 52 | // return expect(resp).to.have.property('message'); 53 | // }); 54 | 55 | // it('should activate Subscription', async function () { 56 | // this.timeout(10000); 57 | 58 | // var payload = { 59 | // id: '11343', 60 | // }; 61 | // var resp = await subscriptionInstance.activate(payload); 62 | // return expect(resp).to.have.property('data'); 63 | // }); 64 | }); 65 | -------------------------------------------------------------------------------- /services/charge/rave.voucher.js: -------------------------------------------------------------------------------- 1 | // const morx = require('morx'); 2 | // const q = require('q'); 3 | // const encrypt = require('./encryp'); 4 | // const axios = require('axios'); 5 | // const package = require('../../package.json'); 6 | 7 | // var spec = morx.spec() 8 | // .build('currency', 'required:true, eg:GBP') 9 | // .build('account_bank', 'required:false') 10 | // .build('amount', 'required:true, eg:10') 11 | // .build('phone_number', 'required:false, eg:08030930236') 12 | // .build('email', 'required:true, eg:debowalefaulkner@gmail.com') 13 | // .build('fullname', 'required:false, eg:lawal garba') 14 | // .build('client_ip', 'required:false, eg:127.0.0.1') 15 | // .build('tx_ref', 'required:false, eg:FLW_y-443342') 16 | // .build('subaccounts', 'required:false') 17 | // .build('meta', 'required:false') 18 | // .build('pin', 'required:true') 19 | // .build('country', 'required:false') 20 | // .build('redirect_url', 'required:false') 21 | // .build('device_fingerprint', 'required:false') 22 | // .build('type', 'required:true eg:ussd') 23 | // .end(); 24 | 25 | // function service(data, _rave) { 26 | // axios.post('https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/staging/sendevent', { 27 | //  "publicKey": _rave.getPublicKey(), 28 | //  "language": "NodeJs v3", 29 | //  "version": package.version, 30 | //  "title": "Incoming call", 31 | //      "message": "Initiate Voucher payment" 32 | // }) 33 | 34 | // var d = q.defer(); 35 | 36 | // q.fcall(() => { 37 | 38 | // var validated = morx.validate(data, spec, _rave.MORX_DEFAULT, {throw_error:true}); 39 | // var params = validated.params; 40 | 41 | // return (params); 42 | 43 | // }) 44 | // .then(params => { 45 | 46 | // return _rave.request('v3/charges?type=voucher_payment', params) 47 | // }) 48 | // .then(response => { 49 | 50 | // d.resolve(response.body); 51 | 52 | // }) 53 | // .catch(err => { 54 | 55 | // d.reject(err); 56 | 57 | // }) 58 | 59 | // return d.promise; 60 | 61 | // } 62 | // service.morxspc = spec; 63 | // module.exports = service; 64 | -------------------------------------------------------------------------------- /lib/security.js: -------------------------------------------------------------------------------- 1 | var createHash = require('sha.js'); 2 | 3 | // this is the getKey function that generates an encryption Key 4 | // for you by passing your Secret Key as a parameter. 5 | function getKey(seckey) { 6 | var md5 = require('md5'); 7 | var keymd5 = md5(seckey); 8 | var keymd5last12 = keymd5.substr(-12); 9 | 10 | var seckeyadjusted = seckey.replace('FLWSECK-', ''); 11 | var seckeyadjustedfirst12 = seckeyadjusted.substr(0, 12); 12 | 13 | return seckeyadjustedfirst12 + keymd5last12; 14 | } 15 | 16 | // This is the encryption function that encrypts your payload 17 | // by passing the stringified format and your encryption Key. 18 | // function encrypt(key, text) 19 | // { 20 | // console.log("Key: "+key) 21 | 22 | // console.log("Txt: "+text) 23 | // var forge = require('node-forge'); 24 | // var cipher = forge.cipher.createCipher('3DES-ECB', forge.util.createBuffer(key)); 25 | // cipher.start({iv:''}); 26 | // cipher.update(forge.util.createBuffer(text, 'utf-8')); 27 | // cipher.finish(); 28 | // var encrypted = cipher.output; 29 | // return ( forge.util.encode64(encrypted.getBytes()) ); 30 | // } 31 | 32 | function encrypt(key, text) { 33 | var forge = require("node-forge"); 34 | var cipher = forge.cipher.createCipher( 35 | "3DES-ECB", 36 | forge.util.createBuffer(key) 37 | ); 38 | cipher.start({ 39 | iv: "" 40 | }); 41 | cipher.update(forge.util.createBuffer(text, "utf-8")); 42 | cipher.finish(); 43 | var encrypted = cipher.output; 44 | return forge.util.encode64(encrypted.getBytes()); 45 | } 46 | 47 | function getIntegrityHash(data, pubkey, seckey) { 48 | 49 | var objectKeys = Object.keys(data); 50 | objectKeys.sort(); 51 | var hashString = ""; 52 | objectKeys 53 | .forEach(function (ok) { 54 | 55 | if (ok == 'integrity_hash') return; // don't include int hash 56 | hashString += data[ok]; 57 | 58 | }); 59 | hashString += seckey; 60 | var hash = createHash('sha256').update(hashString, 'utf8').digest('hex'); 61 | return hash; 62 | } 63 | 64 | 65 | module.exports = { 66 | getEncryptionKey: getKey, 67 | encrypt: encrypt, 68 | getIntegrityHash: getIntegrityHash 69 | } -------------------------------------------------------------------------------- /lib/rave.bills.js: -------------------------------------------------------------------------------- 1 | const amount_to_be_paid = require('../services/bills/rave.amount.to-be-paid'); 2 | const createbill = require('../services/bills/rave.create-bill.payment'); 3 | const create_bulk = require('../services/bills/rave.create-bulk.bills'); 4 | const create_order_billing = require('../services/bills/rave.create-order-billing-code'); 5 | // const get_a_recurring = require('../services/bills/rave.get-a-recurring-bill') 6 | const bills = require('../services/bills/rave.get-bill-payments'); 7 | const bill_cat = require('../services/bills/rave.get.bill-categories'); 8 | const bill_agencies = require('../services/bills/rave.get.bill-payment-agencies'); 9 | // const get_recurring_bills = require ('../services/bills/rave.get.recurrings-bills') 10 | const status = require('../services/bills/rave.get.status'); 11 | const prdts_under_agency = require('../services/bills/rave.products-under-an-agency'); 12 | const update_bills_order = require('../services/bills/rave.update-bills.order'); 13 | const validate_bill = require('../services/bills/rave.validate-bill'); 14 | 15 | function Bills(RaveBase) { 16 | this.create_bill = function (data) { 17 | return createbill(data, RaveBase); 18 | }; 19 | 20 | this.amt_to_be_paid = function (data) { 21 | return amount_to_be_paid(data, RaveBase); 22 | }; 23 | 24 | this.create_bulk = function (data) { 25 | return create_bulk(data, RaveBase); 26 | }; 27 | 28 | this.create_ord_billing = function (data) { 29 | return create_order_billing(data, RaveBase); 30 | }; 31 | 32 | this.fetch_bills = function (data) { 33 | return bills(data, RaveBase); 34 | }; 35 | 36 | this.fetch_bills_Cat = function (data) { 37 | return bill_cat(data, RaveBase); 38 | }; 39 | this.fetch_bills_agencies = function (data) { 40 | return bill_agencies(data, RaveBase); 41 | }; 42 | this.fetch_status = function (data) { 43 | return status(data, RaveBase); 44 | }; 45 | this.products_under_agency = function (data) { 46 | return prdts_under_agency(data, RaveBase); 47 | }; 48 | 49 | this.update_bills = function (data) { 50 | return update_bills_order(data, RaveBase); 51 | }; 52 | 53 | this.validate = function (data) { 54 | return validate_bill(data, RaveBase); 55 | }; 56 | } 57 | module.exports = Bills; 58 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const base = require('./lib/rave.base'); 2 | const bank = require('./lib/rave.banks'); 3 | const beneficiary = require('./lib/rave.beneficiaries'); 4 | const bills = require('./lib/rave.bills'); 5 | const charge = require('./lib/rave.charge'); 6 | const ebills = require('./lib/rave.ebills'); 7 | const misc = require('./lib/rave.misc'); 8 | const mobile_money = require('./lib/rave.mobile_money'); 9 | const security = require('./lib/security'); 10 | // const custom = require("./lib/rave.custom"); 11 | const otps = require('./lib/rave.otps'); 12 | const payment_plan = require('./lib/rave.payment_plan'); 13 | const settlement = require('./lib/rave.settlements'); 14 | const subaccount = require('./lib/rave.subaccount'); 15 | const subscription = require('./lib/rave.subscriptions'); 16 | const tokenized = require('./lib/rave.tokenized'); 17 | const transaction = require('./lib/rave.transactions'); 18 | const transfer = require('./lib/rave.transfers'); 19 | const virtual_acct = require('./lib/rave.virtual_account'); 20 | const virtual_card = require('./lib/rave.virtual_cards'); 21 | 22 | const Rave = function (public_key, public_secret, base_url_or_production_flag) { 23 | const ravebase = new base( 24 | public_key, 25 | public_secret, 26 | base_url_or_production_flag, 27 | ); 28 | 29 | this.Bank = new bank(ravebase); 30 | this.Beneficiary = new beneficiary(ravebase); 31 | this.Bills = new bills(ravebase); 32 | this.Charge = new charge(ravebase); 33 | this.Ebills = new ebills(ravebase); 34 | this.Misc = new misc(ravebase); 35 | this.MobileMoney = new mobile_money(ravebase); 36 | this.security = security; 37 | // this.CustomRequest = new custom(ravebase); 38 | this.Otp = new otps(ravebase); 39 | this.PaymentPlan = new payment_plan(ravebase); 40 | this.Settlement = new settlement(ravebase); 41 | this.Subscription = new subscription(ravebase); 42 | this.Subaccount = new subaccount(ravebase); 43 | this.Tokenized = new tokenized(ravebase); 44 | this.Transaction = new transaction(ravebase); 45 | this.Transfer = new transfer(ravebase); 46 | this.VirtualAcct = new virtual_acct(ravebase); 47 | this.VirtualCard = new virtual_card(ravebase); 48 | 49 | this.getIntegrityHash = function (data) { 50 | return ravebase.getIntegrityHash(data); 51 | }; 52 | }; 53 | 54 | module.exports = Rave; 55 | -------------------------------------------------------------------------------- /services/schema/base.js: -------------------------------------------------------------------------------- 1 | const joi = require('joi'); 2 | 3 | // fetch information with single id. enforce id in payload 4 | const fetchSchema = joi.object({ 5 | id: joi.number().integer().required(), 6 | }); 7 | 8 | // retrieve information with different query parameter. add enforceRequired to enforce query params and validate the request 9 | const listSchema = joi.object({ 10 | id: joi.string(), 11 | page: joi.string().min(1), 12 | index: joi.string().min(1), 13 | size: joi.string().min(1), 14 | from: joi.string().isoDate(), 15 | to: joi.string().isoDate(), 16 | bulk_id: joi.string(), 17 | reference: joi.string(), 18 | tx_ref: joi.string().trim().max(100), 19 | currency: joi.string().uppercase().length(3).default('NGN'), 20 | country: joi.string().uppercase().length(2).default('NG'), 21 | amount: joi.number().positive(), 22 | status: joi.string().max(20), 23 | interval: joi 24 | .string() 25 | .max(20) 26 | .valid('daily', 'weekly', 'monthly', 'quarterly', 'yearly'), 27 | account_bank: joi.string().min(3).max(11), 28 | account_number: joi.string().trim().max(20), 29 | bank_name: joi.string().trim().max(100), 30 | split_value: joi.number().min(0).max(1), 31 | business_name: joi.string().trim().max(100), 32 | business_email: joi.string().email(), 33 | split_type: joi.string().valid('percentage', 'flat'), 34 | subscribed_from: joi.string().isoDate(), 35 | subscribed_to: joi.string().isoDate(), 36 | plan: joi.string().min(1), 37 | customer_fullname: joi.string().max(100), 38 | email: joi.string().max(100).email(), 39 | airtime: joi.number().integer().positive().min(0).max(1), 40 | data_bundle: joi.number().integer().positive().min(0).max(1), 41 | power: joi.number().integer().positive().min(0).max(1), 42 | internet: joi.number().integer().positive().min(0).max(1), 43 | toll: joi.number().integer().positive().min(0).max(1), 44 | cable: joi.number().integer().positive().min(0).max(1), 45 | }); 46 | 47 | // Set id for update 48 | const updateSchema = joi.object({ 49 | id: joi.string().required(), 50 | }); 51 | 52 | // validate collections 53 | const validateSchema = joi.object({ 54 | otp: joi.string().min(5).max(7).required(), 55 | flw_ref: joi.string().required(), 56 | type: joi.string().valid('card', 'account'), 57 | }); 58 | 59 | module.exports = { 60 | fetchSchema, 61 | listSchema, 62 | updateSchema, 63 | validateSchema, 64 | }; 65 | -------------------------------------------------------------------------------- /test/rave.cards.test.js: -------------------------------------------------------------------------------- 1 | // var cards = require('../lib/rave.virtual_cards'); 2 | // var tokenPayments = require('../lib/rave.tokenized'); 3 | // var base = require('../lib/rave.base'); 4 | 5 | // var Promise = require('bluebird'); 6 | // var mocha = require('mocha'); 7 | // var chai = require('chai'); 8 | // var expect = chai.expect; 9 | // var chaiAsPromised = require('chai-as-promised'); 10 | 11 | // var dotenv = require('dotenv').config(); 12 | 13 | // const sinon = require('sinon'); 14 | // const sinonChai = require('sinon-chai'); 15 | 16 | // chai.use(chaiAsPromised); 17 | // chai.use(sinonChai); 18 | 19 | // describe('#Rave Cards issuing', function () { 20 | // const public_key = process.env.PUBLIC_KEY; 21 | // const secret_key = process.env.SECRET_KEY; 22 | // const ravebase = new base(public_key, secret_key); 23 | 24 | // // let trxInstance; 25 | // // let momoStub; 26 | 27 | // beforeEach(() => { 28 | // cardInstance = new cards(ravebase); 29 | // }); 30 | 31 | // afterEach(() => { 32 | // sinon.restore(); 33 | // }); 34 | 35 | // it('should successfully fetch all cards', async function () { 36 | // this.timeout(10000); 37 | // // var payload = { 38 | // // id: '4186265', 39 | // // }; 40 | 41 | // var resp = await cardInstance.fetch_all(); 42 | // // console.log(resp); 43 | // }); 44 | 45 | // it('should successfully fetch card details', async function () { 46 | // this.timeout(10000); 47 | // var payload = { 48 | // id: '776192c3-a85b-4dc4-9620-109877d1f6f8', 49 | // }; 50 | 51 | // var resp = await cardInstance.fetch(payload); 52 | // // console.log(resp); 53 | // }); 54 | 55 | // it('should create a virtual card', async function () { 56 | // this.timeout(10000); 57 | 58 | // var payload = { 59 | // currency: 'USD', 60 | // amount: 5, 61 | // debit_currency: 'NGN', 62 | // billing_name: 'Example User.', 63 | // billing_address: '333, Fremont Street', 64 | // billing_city: 'San Francisco', 65 | // billing_state: 'CA', 66 | // billing_postal_code: '94105', 67 | // billing_country: 'US', 68 | // first_name: 'Example', 69 | // last_name: 'User', 70 | // date_of_birth: '1996/12/30', 71 | // email: 'userg@example.com', 72 | // phone: '07030000000', 73 | // title: 'Mr', 74 | // gender: 'M', 75 | // callback_url: 'https://webhook.site/b67965fa-e57c-4dda-84ce-0f8d6739b8a5', 76 | // }; 77 | 78 | // var resp = await cardInstance.create(payload); 79 | // // console.log(resp); 80 | // }); 81 | // }); 82 | -------------------------------------------------------------------------------- /views/index.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title RavePay 5 | //- link(rel="stylesheet", href="/bower_components/bootstrap/dist/css/bootstrap.css") 6 | //- link(rel="stylesheet", href="/css/style.css") 7 | 8 | body 9 | .container 10 | block content 11 | h1 #{title} 12 | 13 | form 14 | script(src='https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/hosted/pay') 15 | button(type='button', onclick='payWithRave()') Pay Now 16 | script. 17 | const API_publicKey = "FLWPUBK-xxxxxxxxxxxxxxxxxxxxx-X"; 18 | function payWithRave() { 19 | var x = getpaidSetup({ 20 | PBFPubKey: API_publicKey, 21 | customer_email: "user@example.com", 22 | amount: 2000, 23 | customer_phone: "234099940409", 24 | currency: "NGN", 25 | payment_options: "card,account", 26 | txref: "rave-123456", 27 | hosted_payment: 1, 28 | //- redirect_url: "https://your-website.com/url-to-redirect-to" 29 | meta: [{ 30 | metaname: "flightID", 31 | metavalue: "AP1234" 32 | }], 33 | onclose: function() {}, 34 | callback: function(response) { 35 | var txref = response.tx.txRef; // collect txRef returned and pass to a server page to complete status check. 36 | console.log("This is the response returned after a charge", response); 37 | if ( 38 | response.tx.chargeResponseCode == "00" || 39 | response.tx.chargeResponseCode == "0" 40 | ) { 41 | // redirect to a success page 42 | } else { 43 | // redirect to a failure page. 44 | } 45 | x.close(); // use this to close the modal immediately after payment. 46 | } 47 | }); 48 | } 49 | 50 | br 51 | hr 52 | footer 53 | p copyright © 2019 54 | 55 | //- script(src='/bower_components/bootstrap/js/dist/dropdown.js') 56 | //- script(src='/bower_components/bootstrap/dist/js/bootstrap.js') 57 | 58 | -------------------------------------------------------------------------------- /services/schema/bill.js: -------------------------------------------------------------------------------- 1 | const joi = require('joi'); 2 | 3 | const amountQuerySchema = joi.object({ 4 | id: joi.string().required(), 5 | product_id: joi.string().required(), 6 | }); 7 | 8 | const createSchema = joi.object({ 9 | country: joi.string().uppercase().length(2).default('NG'), 10 | amount: joi.number().positive().required(), 11 | customer: joi.string().required(), 12 | recurrence: joi.string().required(), 13 | reference: joi.string().required(), 14 | type: joi.string(), 15 | }); 16 | 17 | const bulkCreateSchema = joi.object({ 18 | bulk_reference: joi.string().required(), 19 | callback_url: joi.string().uri().required(), 20 | bulk_data: joi 21 | .array() 22 | .items( 23 | joi.object({ 24 | country: joi.string().required(), 25 | customer: joi.string().required(), 26 | amount: joi.number().positive().required(), 27 | recurrence: joi.string().valid('WEEKLY', 'MONTHLY').required(), 28 | type: joi.string().required(), 29 | reference: joi.string().required(), 30 | }), 31 | ) 32 | .min(1) 33 | .required(), 34 | }); 35 | 36 | const createOrderSchema = joi.object({ 37 | id: joi.string().required(), 38 | product_id: joi.string().required(), 39 | amount: joi.number().positive().required(), 40 | country: joi.string().required(), 41 | reference: joi.string().trim().max(100).required(), 42 | customer: joi 43 | .object({ 44 | name: joi.string().required(), 45 | email: joi.string().email().required(), 46 | phone_number: joi 47 | .string() 48 | .max(50) 49 | .custom((value) => { 50 | if (value && !/^\+?\d+$/.test(value)) 51 | throw new Error('phone number should be digits'); 52 | return value; 53 | }) 54 | .required(), 55 | }) 56 | .required(), 57 | fields: joi 58 | .array() 59 | .items( 60 | joi.object({ 61 | id: joi.string(), 62 | quantity: joi.string(), 63 | value: joi.string(), 64 | }), 65 | ) 66 | .required(), 67 | }); 68 | 69 | const fetchStatusSchema = joi.object({ 70 | reference: joi.string().trim().max(100).required(), 71 | }); 72 | 73 | const updateOrderSchema = joi.object({ 74 | amount: joi.number().required(), 75 | order_id: joi.string().trim().max(100).required(), 76 | reference: joi.string().trim().max(100).required(), 77 | }); 78 | 79 | const validateSchema = joi.object({ 80 | code: joi.string().trim().max(100).required(), 81 | item_code: joi.string().trim().max(100).required(), 82 | customer: joi.string().trim().max(100).required(), 83 | }); 84 | 85 | module.exports = { 86 | amountQuerySchema, 87 | createSchema, 88 | bulkCreateSchema, 89 | createOrderSchema, 90 | fetchStatusSchema, 91 | updateOrderSchema, 92 | validateSchema, 93 | }; 94 | -------------------------------------------------------------------------------- /documentation/ebills.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # EBILLS 6 | 7 | We recommend reading the main readme first, to understand the requirements for using the library and how to initiate this in your apps. This guide assumes you've read that. 8 | 9 | Manage Ebills via any of these methods: 10 | 1. [Place Ebills Order](#place-ebills-order) 11 | 2. [Update Ebills Order](#update-ebills-order) 12 | 13 | ## Place ebills order 14 | 15 | This describes how to create a new Ebills order 16 | 17 | ```javascript 18 | 19 | const Flutterwave = require('flutterwave-node-v3'); 20 | 21 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 22 | 23 | const placeEbillsOrder = async () => { 24 | 25 | try { 26 | 27 | const payload = { 28 | "narration": "mndkn blls", 29 | "number_of_units": 2, 30 | "currency": "NGN", 31 | "amount": 100, 32 | "phone_number": "09384747474", 33 | "email": "jake@rad.com", 34 | "tx_ref": "akhlm-pstmn-109470393", 35 | "ip": "127.9.0.7", 36 | "custom_business_name": "John Madakin", 37 | "country": "NG" 38 | } 39 | 40 | const response = await flw.Ebills.order(payload) 41 | console.log(response); 42 | } catch (error) { 43 | console.log(error) 44 | } 45 | 46 | } 47 | 48 | 49 | placeEbillsOrder(); 50 | ``` 51 | 52 | Sample Response 53 | 54 | ```javascript 55 | { 56 | "status": "success", 57 | "message": "Ebills ordered", 58 | "data": { 59 | "flw_ref": "RVEBLS-F35542EA3BFE-73362", 60 | "tx_ref": "akhlm-pstmn-109470393", 61 | "response_message": "Pending funds transfer or bank branch payment" 62 | } 63 | } 64 | ``` 65 | 66 | 67 | 68 | ## Update ebills order 69 | 70 | This describes how to update order for ebills 71 | 72 | ```javascript 73 | 74 | const Flutterwave = require('flutterwave-node-v3'); 75 | 76 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 77 | 78 | 79 | const updateEbillsOrder = async () => { 80 | 81 | try { 82 | 83 | const payload = { 84 | "reference": "RVEBLS-843984E9B66E-23240", //This is the reference returned in the create order endpoint as flw_ref. 85 | "currency": "NGN", 86 | "amount": 4000 87 | } 88 | 89 | const response = await flw.Ebills.update(payload) 90 | console.log(response); 91 | } catch (error) { 92 | console.log(error) 93 | } 94 | 95 | } 96 | 97 | 98 | updateEbillsOrder(); 99 | ``` 100 | 101 | Sample Response 102 | 103 | ```javascript 104 | { 105 | "status": "success", 106 | "message": "Ebills order updated", 107 | "data": { 108 | "updated": true 109 | } 110 | } 111 | ``` 112 | -------------------------------------------------------------------------------- /documentation/otp.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # OTPS 6 | 7 | We recommend reading the main readme first, to understand the requirements for using the library and how to initiate this in your apps. This guide assumes you've read that. 8 | 9 | Manage Otps via any of these methods: 10 | 1. [Create Otp](#create-otp) 11 | 2. [Validate Otp](#validate-otp) 12 | 13 | 14 | ## Create Otp 15 | 16 | This describes how to create an otp 17 | 18 | ```javascript 19 | 20 | const Flutterwave = require('flutterwave-node-v3'); 21 | 22 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 23 | 24 | const createOTP = async () => { 25 | 26 | try { 27 | 28 | const payload = { 29 | "length": 7, 30 | "customer": { 31 | "name": "Kazan", 32 | "email": "kazan@mailinator.com", 33 | "phone": "2348131149273" 34 | }, 35 | "sender": "Test Sender", 36 | "send": true, 37 | "medium": [ 38 | "email", 39 | "whatsapp" 40 | ], 41 | "expiry": 5 42 | } 43 | 44 | const response = await flw.Otp.create(payload) 45 | console.log(response); 46 | } catch (error) { 47 | console.log(error) 48 | } 49 | 50 | } 51 | 52 | 53 | createOTP(); 54 | ``` 55 | 56 | Sample Response 57 | 58 | ```javascript 59 | { 60 | "status": "success", 61 | "message": "OTP generated successfully", 62 | "data": [ 63 | { 64 | "medium": "email", 65 | "reference": "CF-BARTER-20230305031441503636", 66 | "otp": "1495545", 67 | "expiry": "2023-03-05T03:19:41.8110726+00:00" 68 | }, 69 | { 70 | "medium": "whatsapp", 71 | "reference": "CF-BARTER-20230305031443536582", 72 | "otp": "1495545", 73 | "expiry": "2023-03-05T03:19:43.4362097+00:00" 74 | } 75 | ] 76 | } 77 | ``` 78 | 79 | 80 | ## Validate Otp 81 | 82 | This describes how to validate an otp 83 | 84 | ```javascript 85 | 86 | const Flutterwave = require('flutterwave-node-v3'); 87 | 88 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 89 | 90 | 91 | const validateOTP = async () => { 92 | 93 | try { 94 | 95 | const payload = { 96 | "reference": "CF-BARTER-20190420022611377491", 97 | "otp": "481208" 98 | } 99 | 100 | const response = await flw.Otp.validate(payload) 101 | console.log(response); 102 | } catch (error) { 103 | console.log(error) 104 | } 105 | 106 | } 107 | 108 | 109 | validateOTP(); 110 | ``` 111 | 112 | Sample Response 113 | 114 | ```javascript 115 | { 116 | "status": "success", 117 | "message": "Otp Authenticated successfully", 118 | "data": null 119 | } 120 | ``` 121 | 122 | -------------------------------------------------------------------------------- /test/rave.ebills.test.js: -------------------------------------------------------------------------------- 1 | var ebills = require('../lib/rave.ebills'); 2 | var base = require('../lib/rave.base'); 3 | 4 | var Promise = require('bluebird'); 5 | var mocha = require('mocha'); 6 | var chai = require('chai'); 7 | var expect = chai.expect; 8 | var chaiAsPromised = require('chai-as-promised'); 9 | 10 | var dotenv = require('dotenv').config(); 11 | 12 | const sinon = require('sinon'); 13 | const sinonChai = require('sinon-chai'); 14 | 15 | chai.use(chaiAsPromised); 16 | chai.use(sinonChai); 17 | 18 | describe('#Rave Ebills', function () { 19 | const public_key = process.env.PUBLIC_KEY; 20 | const secret_key = process.env.SECRET_KEY; 21 | const ravebase = new base(public_key, secret_key); 22 | 23 | let ebillsInstance; 24 | let ebillsStub; 25 | 26 | beforeEach(() => { 27 | ebillsInstance = new ebills(ravebase); 28 | }); 29 | 30 | afterEach(() => { 31 | sinon.restore(); 32 | }); 33 | 34 | it('should create a new Ebills order ', async function () { 35 | this.timeout(10000); 36 | 37 | const createEbillsSuccessStub = sinon 38 | .stub(ebillsInstance, 'order') 39 | .resolves({ 40 | body: { 41 | status: 'success', 42 | message: 'Ebills ordered', 43 | data: { 44 | flw_ref: 'RVEBLS-F35542EA3BFE-73362', 45 | tx_ref: 'akhlm-pstmn-109470393', 46 | response_message: 'Pending funds transfer or bank branch payment', 47 | }, 48 | }, 49 | }); 50 | 51 | var payload = { 52 | narration: 'mndkn blls', 53 | number_of_units: 2, 54 | currency: 'NGN', 55 | amount: 100, 56 | phone_number: '09384747474', 57 | email: 'jake@rad.com', 58 | tx_ref: 'akhlm-pstmn-109470393', 59 | ip: '127.9.0.7', 60 | custom_business_name: 'John Madakin', 61 | country: 'NG', 62 | }; 63 | 64 | var resp = await ebillsInstance.order(payload); 65 | 66 | expect(createEbillsSuccessStub).to.have.been.calledOnce; 67 | expect(createEbillsSuccessStub).to.have.been.calledOnceWith(payload); 68 | 69 | expect(resp.body).to.have.property('status', 'success'); 70 | expect(resp.body).to.have.property('data'); 71 | 72 | expect(resp.body.data).to.have.property('flw_ref'); 73 | expect(resp.body.data).to.have.property('tx_ref'); 74 | expect(resp.body.data).to.have.property('response_message'); 75 | }); 76 | 77 | it('should return list of bank branches ', async function () { 78 | this.timeout(10000); 79 | 80 | const updateEbillsSuccessStub = sinon 81 | .stub(ebillsInstance, 'update') 82 | .resolves({ 83 | body: { 84 | status: 'success', 85 | message: 'Ebills order updated', 86 | data: { 87 | updated: true, 88 | }, 89 | }, 90 | }); 91 | 92 | var payload = { 93 | currency: 'NGN', 94 | amount: 4000, 95 | reference: 'RVEBLS-F81CEEEE8218-73362', 96 | }; 97 | 98 | var resp = await ebillsInstance.update(payload); 99 | 100 | expect(updateEbillsSuccessStub).to.have.been.calledOnce; 101 | expect(updateEbillsSuccessStub).to.have.been.calledOnceWith(payload); 102 | 103 | expect(resp.body).to.have.property('status', 'success'); 104 | expect(resp.body).to.have.property('data'); 105 | }); 106 | }); 107 | -------------------------------------------------------------------------------- /test/rave.otp.test.js: -------------------------------------------------------------------------------- 1 | var otp = require('../lib/rave.otps'); 2 | var base = require('../lib/rave.base'); 3 | 4 | var Promise = require('bluebird'); 5 | var mocha = require('mocha'); 6 | var chai = require('chai'); 7 | var expect = chai.expect; 8 | var chaiAsPromised = require('chai-as-promised'); 9 | 10 | var dotenv = require('dotenv').config(); 11 | 12 | const sinon = require('sinon'); 13 | const sinonChai = require('sinon-chai'); 14 | 15 | chai.use(chaiAsPromised); 16 | chai.use(sinonChai); 17 | 18 | describe('#Rave OTP', function () { 19 | const public_key = process.env.PUBLIC_KEY; 20 | const secret_key = process.env.SECRET_KEY; 21 | const ravebase = new base(public_key, secret_key); 22 | 23 | let otpInstance; 24 | let otpStub; 25 | 26 | beforeEach(() => { 27 | otpInstance = new otp(ravebase); 28 | }); 29 | 30 | afterEach(() => { 31 | sinon.restore(); 32 | }); 33 | 34 | it('should generate OTP and return success message', async function () { 35 | this.timeout(10000); 36 | 37 | const generateOTPSuccessStub = sinon.stub(otpInstance, 'create').resolves({ 38 | body: { 39 | status: 'success', 40 | message: 'OTP generated successfully', 41 | data: [ 42 | { 43 | medium: 'email', 44 | reference: 'CF-BARTER-20230305031441503636', 45 | otp: '1495545', 46 | expiry: '2023-03-05T03:19:41.8110726+00:00', 47 | }, 48 | { 49 | medium: 'whatsapp', 50 | reference: 'CF-BARTER-20230305031443536582', 51 | otp: '1495545', 52 | expiry: '2023-03-05T03:19:43.4362097+00:00', 53 | }, 54 | ], 55 | }, 56 | }); 57 | 58 | var payload = { 59 | length: 7, 60 | customer: { 61 | name: 'Kazan', 62 | email: 'kazan@mailinator.com', 63 | phone: '2348131149273', 64 | }, 65 | sender: 'Test Sender', 66 | send: true, 67 | medium: ['email', 'whatsapp'], 68 | expiry: 5, 69 | }; 70 | 71 | var resp = await otpInstance.create(payload); 72 | // console.log(resp); 73 | 74 | expect(generateOTPSuccessStub).to.have.been.calledOnce; 75 | expect(generateOTPSuccessStub).to.have.been.calledOnceWith(payload); 76 | 77 | expect(resp.body).to.have.property('status', 'success'); 78 | expect(resp.body).to.have.property('data'); 79 | expect(resp.body.message).to.eq('OTP generated successfully'); 80 | 81 | expect(resp.body.data[0]).to.have.property('medium'); 82 | expect(resp.body.data[0]).to.have.property('reference'); 83 | expect(resp.body.data[0]).to.have.property('expiry'); 84 | }); 85 | 86 | it('should validate OTP and return success message', async function () { 87 | this.timeout(10000); 88 | 89 | const validateOTPSuccessStub = sinon 90 | .stub(otpInstance, 'validate') 91 | .resolves({ 92 | body: { 93 | status: 'success', 94 | message: 'Otp Authenticated successfully', 95 | data: null, 96 | }, 97 | }); 98 | 99 | var payload = { 100 | reference: 'CF-BARTER-20230305031441503636', 101 | otp: '1495545', 102 | }; 103 | 104 | var resp = await otpInstance.validate(payload); 105 | // console.log(resp); 106 | 107 | expect(validateOTPSuccessStub).to.have.been.calledOnce; 108 | expect(validateOTPSuccessStub).to.have.been.calledOnceWith(payload); 109 | 110 | expect(resp.body).to.have.property('status', 'success'); 111 | expect(resp.body).to.have.property('data'); 112 | expect(resp.body.message).to.eq('Otp Authenticated successfully'); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | Thank you for taking the time to contribute to our library🙌🏾. 6 | 7 | In this section, we detail everything you need to know about contributing to this library. 8 | 9 | 10 | **[Code of Conduct](https://github.com/probot/template/blob/master/CODE_OF_CONDUCT.md)** 11 | 12 | ## **I don't want to contribute, I have a question** 13 | 14 | Please don't raise an issue to ask a question. You can ask questions on our [forum](http://forum.flutterwave.com) or developer [slack](https://bit.ly/34Vkzcg). We have an army of Engineers on hand to answer your questions there. 15 | 16 | ## How can I contribute? 17 | 18 | ### Reporting a bug 19 | 20 | Have you spotted a bug? Fantastic! Before raising an issue, here are some things to do: 21 | 22 | 1. Search to see if another user has reported the bug. For existing issues that are still open, add a comment instead of creating a new one. 23 | 2. Check our forum and developer slack to confirm that we did not address it there. 24 | 25 | When you report an issue, it is important to: 26 | 27 | 1. Explain the problem 28 | - Use a clear and descriptive title to help us to identify the problem. 29 | - Describe steps we can use to replicate the bug and be as precise as possible. 30 | - Include screenshots of the error messages. 31 | 2. Include details about your configuration and setup 32 | - What version of the library are you using? 33 | - Did you experience the bug on test mode or live? 34 | - Do you have the recommended versions of the library dependencies? 35 | 36 | 41 | 42 | ### Requesting a feature 43 | 44 | If you need an additional feature added to the library, kindly send us an email at developers@flutterwavego.com. Be sure to include the following in your request: 45 | 46 | 1. A clear title that helps us to identify the requested feature. 47 | 2. A brief description of the use case for that feature. 48 | 3. Explain how this feature would be helpful to your integration. 49 | 4. Library name and version. 50 | 51 | ### Submitting changes (PR) 52 | 53 | Generally, you can make any of the following changes to the library: 54 | 55 | 1. Bug fixes 56 | 2. Performance improvement 57 | 3. Documentation update 58 | 4. Functionality change (usually new features) 59 | 60 | 65 | 66 | Follow these steps when making a pull request to the library: 67 | 68 | 1. Fork the repository and create your branch from master. 69 | 2. For all types of changes (excluding documentation updates), add tests for the changes. 70 | 3. If you are making a functionality change, update the docs to show how to use the new feature. 71 | 4. Ensure all your tests pass. 72 | 5. Make sure your code lints. 73 | 6. Write clear log messages for your commits. one-liners are fine for small changes, but bigger changes should have a more descriptive commit message (see sample below). 74 | 7. Use present tense for commit messages, "Add feature" not "Added feature”. 75 | 8. Ensure that you fill out all sections of the PR template. 76 | 9. Raise the PR against the `staging` branch. 77 | 10. After you submit the PR, verify that all [status checks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks) are passing 78 | 79 | ```markdown 80 | $ git commit -m "A brief summary of the commit 81 | > 82 | > A paragraph describing what changed and its impact." 83 | ``` 84 | 85 | 90 | 91 | We encourage you to contribute and help make the library better for the community. Got questions? send us a [message](https://bit.ly/34Vkzcg). 92 | 93 | Thank you. 94 | 95 | The Flutterwave team 🦋 -------------------------------------------------------------------------------- /test/rave.bank.test.js: -------------------------------------------------------------------------------- 1 | var banks = require('../lib/rave.banks'); 2 | var base = require('../lib/rave.base'); 3 | 4 | var Promise = require('bluebird'); 5 | var mocha = require('mocha'); 6 | var chai = require('chai'); 7 | var expect = chai.expect; 8 | var chaiAsPromised = require('chai-as-promised'); 9 | 10 | var dotenv = require('dotenv').config(); 11 | 12 | const sinon = require('sinon'); 13 | const sinonChai = require('sinon-chai'); 14 | 15 | chai.use(chaiAsPromised); 16 | chai.use(sinonChai); 17 | 18 | describe('#Rave Bank', function () { 19 | const public_key = process.env.PUBLIC_KEY; 20 | const secret_key = process.env.SECRET_KEY; 21 | const ravebase = new base(public_key, secret_key); 22 | 23 | let banksInstance; 24 | let bankStub; 25 | 26 | beforeEach(() => { 27 | banksInstance = new banks(ravebase); 28 | }); 29 | 30 | afterEach(() => { 31 | sinon.restore(); 32 | }); 33 | 34 | it('should return list of banks in NG ', async function () { 35 | this.timeout(10000); 36 | 37 | const bankStub = sinon.stub(banksInstance, 'country').resolves({ 38 | body: { 39 | status: 'success', 40 | message: 'Banks fetched successfully', 41 | data: [ 42 | { 43 | id: 1, 44 | code: '044', 45 | name: 'Access Bank', 46 | }, 47 | { 48 | id: 2, 49 | code: '023', 50 | name: 'Citi Bank', 51 | }, 52 | { 53 | id: 4, 54 | code: '050', 55 | name: 'EcoBank PLC', 56 | }, 57 | { 58 | id: 5, 59 | code: '011', 60 | name: 'First Bank PLC', 61 | }, 62 | { 63 | id: 6, 64 | code: '214', 65 | name: 'First City Monument Bank', 66 | }, 67 | ], 68 | }, 69 | }); 70 | 71 | var payload = { 72 | country: 'NG', 73 | }; 74 | 75 | var resp = await banksInstance.country(payload); 76 | // console.log(resp); 77 | 78 | expect(bankStub).to.have.been.calledOnce; 79 | expect(bankStub).to.have.been.calledOnceWith(payload); 80 | 81 | expect(resp.body).to.have.property('status', 'success'); 82 | expect(resp.body).to.have.property('data'); 83 | 84 | expect(resp.body.data[0]).to.have.property('id'); 85 | expect(resp.body.data[0]).to.have.property('code'); 86 | expect(resp.body.data[0]).to.have.property('name'); 87 | }); 88 | 89 | it('should return list of bank branches ', async function () { 90 | this.timeout(10000); 91 | 92 | const bankBranchStub = sinon.stub(banksInstance, 'branches').resolves({ 93 | body: { 94 | status: 'success', 95 | message: 'Banks fetched successfully', 96 | data: [ 97 | { 98 | id: 1804, 99 | branch_code: 'UG240647', 100 | branch_name: 'BWAISE BRANCH', 101 | swift_code: 'GLTBUGKA', 102 | bic: '', 103 | bank_id: 280, 104 | }, 105 | { 106 | id: 1805, 107 | branch_code: 'UG240547', 108 | branch_name: 'MUKONO BRANCH', 109 | swift_code: 'GLTBUGKA', 110 | bic: '', 111 | bank_id: 280, 112 | }, 113 | { 114 | id: 1806, 115 | branch_code: 'UG240447', 116 | branch_name: 'NATETE BRANCH', 117 | swift_code: 'GLTBUGKA', 118 | bic: '', 119 | bank_id: 280, 120 | }, 121 | { 122 | id: 1807, 123 | branch_code: 'UG240347', 124 | branch_name: 'PARLIAMENT BRANCH', 125 | swift_code: 'GLTBUGKA', 126 | bic: '', 127 | bank_id: 280, 128 | }, 129 | ], 130 | }, 131 | }); 132 | 133 | var payload = { 134 | id: '280', 135 | }; 136 | 137 | var resp = await banksInstance.branches(payload); 138 | // console.log(resp); 139 | 140 | expect(bankBranchStub).to.have.been.calledOnce; 141 | expect(bankBranchStub).to.have.been.calledOnceWith(payload); 142 | 143 | expect(resp.body).to.have.property('status', 'success'); 144 | expect(resp.body).to.have.property('data'); 145 | 146 | expect(resp.body.data[0]).to.have.property('id'); 147 | expect(resp.body.data[0]).to.have.property('branch_code'); 148 | expect(resp.body.data[0]).to.have.property('branch_name'); 149 | expect(resp.body.data[0]).to.have.property('swift_code'); 150 | expect(resp.body.data[0]).to.have.property('bank_id'); 151 | }); 152 | }); 153 | 154 | 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Flutterwave v3 NodeJS Library 6 | 7 | ![npm](https://img.shields.io/npm/v/flutterwave-node-v3) 8 | ![npm](https://img.shields.io/npm/dt/flutterwave-node-v3) 9 | ![NPM](https://img.shields.io/npm/l/flutterwave-node-v3) 10 | 11 | ## Introduction 12 | 13 | The Node library provides easy access to Flutterwave for Business (F4B) v3 APIs for your Node apps. It abstracts the complexity involved in direct integration and allows you to make quick calls to the APIs. 14 | Available features include: 15 | 16 | - Collections: Card, Account, Mobile money, Bank Transfers, USSD, Apple Pay, Google Pay, Fawry Pay, eNaira. 17 | - Payouts and Beneficiaries. 18 | - Recurring payments: Tokenization and Subscriptions. 19 | - Split payments 20 | - Card issuing 21 | - Transactions dispute management: Refunds and Chargebacks. 22 | - Transaction reporting: Collections, Payouts, Settlements, Refunds, Chargebacks and Transaction timeline. 23 | - Bill payments: Airtime, Data bundle, Cable, Power, Toll, E-bills, and Remitta. 24 | - Identity verification: Resolve bank account, resolve BVN information and generate OTP. 25 | 26 | ## Table of Contents 27 | 28 | 1. [Requirements](#requirements) 29 | 2. [Installation](#installation) 30 | 3. [Initialization](#initialization) 31 | 4. [Usage](#usage) 32 | 5. [Testing](#testing) 33 | 6. [Debugging Errors](#debugging-errors) 34 | 7. [Support](#support) 35 | 8. [Contribution guidelines](#contribution-guidelines) 36 | 9. [License](#license) 37 | 10. [Changelog](/CHANGELOG.md) 38 | 39 | ## Requirements 40 | 41 | 1. Flutterwave for business (F4B) [API Keys](https://developer.flutterwave.com/docs/integration-guides/authentication) 42 | 2. Node 18 or higher. 43 | 44 | ## Installation 45 | 46 | To install the package, run the following command in your Node terminal: 47 | 48 | ```sh 49 | npm install flutterwave-node-v3 50 | ``` 51 | 52 | ## Initialization 53 | 54 | ```javascript 55 | const Flutterwave = require('flutterwave-node-v3'); 56 | const flw = new Flutterwave( 57 | process.env.FLW_PUBLIC_KEY, 58 | process.env.FLW_SECRET_KEY, 59 | ); 60 | ``` 61 | 62 | For staging (Test environment), use the TEST API Keys and for production (Live environment), use LIVE API KEYS. 63 | You can get your process.env.FLW_PUBLIC_KEY and process.env.FLW_SECRET_KEY from the Flutterwave dashboard. Read the [requirement section](#requirements) for more information on how to get your API keys. 64 | 65 | ## Usage 66 | 67 | 1. [Collections](documentation/collections.md) 68 | 2. [Tokenization](documentation/tokenization.md) 69 | 3. [Subscriptions](documentation/subscription.md) 70 | 4. [Transfers](documentation/transfers.md) 71 | 5. [Virtual Account](documentation/virtualAccount.md) 72 | 6. [Bill payments](documentation/billPayments.md) 73 | 7. [Transactions and reporting](documentation/transactions.md) 74 | 8. [Beneficiaries](documentation/beneficiary.md) 75 | 9. [Banks](documentation/banks.md) 76 | 10. [Settlements](documentation/settlements.md) 77 | 11. [OTP](documentation/otp.md) 78 | 12. [Ebills](documentation/ebills.md) 79 | 13. [Misc](documentation/misc.md) 80 | 14. [Virtual Cards](documentation/virtualCard.md) 81 | 15. [Collection Subaccounts](documentation/subaccount.md) 82 | 16. [Payment-plan](documentation/payment-plan.md) 83 | 84 | ## Testing 85 | 86 | All of the libraries tests are run on Mocha. Available tests include `rave.bank.test`, `rave.beneficiaries.test`, `rave.bills.test`, `rave.charge.test`, `rave.ebills.test`, `rave.settlements.test`, `rave.subscriptions.test`. They can be run by running the test command in your terminal. 87 | 88 | ```sh 89 | npm run test or npm test 90 | ``` 91 | 92 | ## Debugging Errors 93 | 94 | We understand that you may run into some errors while integrating our library. You can read more about our error messages [here](https://developer.flutterwave.com/docs/integration-guides/errors). 95 | For `authorization` and `validation` error responses, double-check your API keys and request. If you get a `server` error, kindly engage the team for support. 96 | 97 | ## Support 98 | 99 | For additional assistance using this library, contact the developer experience (DX) team via [email](mailto:developers@flutterwavego.com) or on [slack](https://bit.ly/34Vkzcg). 100 | You can also follow us [@FlutterwaveEng](https://twitter.com/FlutterwaveEng) and let us know what you think 😊. 101 | 102 | ## Contribution guidelines 103 | 104 | Read more about our community contribution guidelines [here](/CONTRIBUTING.md) 105 | 106 | ## License 107 | 108 | By contributing to this library, you agree that your contributions will be licensed under its [MIT license](/LICENSE). 109 | Copyright (c) Flutterwave Inc. 110 | -------------------------------------------------------------------------------- /services/schema/auxillary.js: -------------------------------------------------------------------------------- 1 | const joi = require('joi'); 2 | 3 | // create an OTP 4 | const createOTPSchema = joi.object({ 5 | length: joi.number().integer().min(1).required(), 6 | customer: joi 7 | .object({ 8 | name: joi.string().required(), 9 | email: joi.string().email().required(), 10 | phone: joi.string().required(), 11 | }) 12 | .required(), 13 | sender: joi.string().required(), 14 | send: joi.boolean().required(), 15 | medium: joi 16 | .array() 17 | .items(joi.string().valid('email', 'whatsapp', 'sms')) 18 | .required(), 19 | expiry: joi.number().integer().min(1), 20 | }); 21 | 22 | // query transaction fees 23 | const feeSchema = joi.object({ 24 | currency: joi.string().uppercase().length(3).default('NGN').required(), 25 | amount: joi.number().positive().required(), 26 | payment_type: joi 27 | .string() 28 | .max(20) 29 | .valid( 30 | 'card', 31 | 'debit_ng_account', 32 | 'mobilemoney', 33 | 'bank_transfer', 34 | 'ach_payment', 35 | ), 36 | card_first6digits: joi.string().length(6), 37 | }); 38 | 39 | // fetch account details 40 | const fetchAccountSchema = joi.object({ 41 | order_ref: joi.string().trim().max(100).required(), 42 | }); 43 | 44 | // fetch balance 45 | const fetchBalance = joi.object({ 46 | currency: joi.string().uppercase().length(3).default('NGN').required(), 47 | }); 48 | 49 | // fetch bulk account details 50 | const fetchBulkAccountSchema = joi.object({ 51 | batch_id: joi.string().trim().max(100).required(), 52 | }); 53 | 54 | // fund a virtual card 55 | const fundSchema = joi.object({ 56 | id: joi.string().required(), 57 | debit_currency: joi.string().uppercase().length(3).default('NGN').required(), 58 | amount: joi.number().required(), 59 | }); 60 | 61 | // create an ebill order 62 | const orderSchema = joi.object({ 63 | email: joi.string().max(100).email().required(), 64 | tx_ref: joi.string().trim().max(100).required(), 65 | ip: joi 66 | .string() 67 | .ip({ 68 | version: ['ipv4', 'ipv6'], 69 | }) 70 | .default('::127.0.0.1'), 71 | custom_business_name: joi.string().trim().max(100).required(), 72 | amount: joi.number().positive().required(), 73 | currency: joi.string().uppercase().length(3).default('NGN'), 74 | country: joi.string().uppercase().length(2).default('NG'), 75 | number_of_units: joi.number().required(), 76 | phone_number: joi 77 | .string() 78 | .max(50) 79 | .custom((value) => { 80 | if (value && !/^\+?\d+$/.test(value)) 81 | throw new Error('phone number should be digits'); 82 | return value; 83 | }), 84 | }); 85 | 86 | // resolve account details 87 | const resolveSchema = joi.object({ 88 | account_bank: joi.string().min(3).max(11).required(), 89 | account_number: joi.string().required(), 90 | country: joi.string().uppercase().length(2).default('NG'), 91 | type: joi.string(), 92 | }); 93 | 94 | // fetch tokenization data: bulk tokens and transaction list 95 | const retrieveSchema = joi.object({ 96 | bulk_id: joi.string().required(), 97 | }); 98 | 99 | // update details on ebill orders 100 | const updateSchema = joi.object({ 101 | reference: joi.string().trim().max(100).required(), 102 | amount: joi.number().positive().required(), 103 | currency: joi.string().uppercase().length(3).default('NGN'), 104 | }); 105 | 106 | // update payment plan details 107 | const updatePlanSchema = joi.object({ 108 | id: joi.string().required(), 109 | name: joi.string().trim().max(150).required(), 110 | status: joi.string().valid('active', 'cancelled').required() 111 | }); 112 | 113 | // update card token 114 | const updateTokenSchema = joi.object({ 115 | token: joi.string().required(), 116 | email: joi.string().email().required(), 117 | phone_number: joi 118 | .string() 119 | .max(50) 120 | .custom((value) => { 121 | if (value && !/^\+?\d+$/.test(value)) 122 | throw new Error('phone number should be digits'); 123 | return value; 124 | }) 125 | .required(), 126 | full_name: joi.string().required(), 127 | }); 128 | 129 | // withdraw funds from a virtual card 130 | const withdrawalSchema = joi.object({ 131 | id: joi.string().required(), 132 | amount: joi.number().required(), 133 | }); 134 | 135 | // Validate an OTP 136 | const validateSchema = joi.object({ 137 | reference: joi.string().trim().max(100).required(), 138 | otp: joi.number().required(), 139 | }); 140 | 141 | // validate a BVN 142 | const initiateBVNSchema = joi.object({ 143 | bvn: joi.string().length(11).required(), 144 | firstname: joi.string().max(100).required(), 145 | lastname: joi.string().max(100).required(), 146 | redirect_url: joi.string().uri(), 147 | }); 148 | 149 | const verifyBVNSchema = joi.object({ 150 | reference: joi.string().trim().max(100).required(), 151 | }); 152 | 153 | module.exports = { 154 | createOTPSchema, 155 | feeSchema, 156 | fetchAccountSchema, 157 | fetchBalance, 158 | fetchBulkAccountSchema, 159 | fundSchema, 160 | orderSchema, 161 | resolveSchema, 162 | retrieveSchema, 163 | updateSchema, 164 | updatePlanSchema, 165 | updateTokenSchema, 166 | withdrawalSchema, 167 | validateSchema, 168 | initiateBVNSchema, 169 | verifyBVNSchema 170 | }; 171 | -------------------------------------------------------------------------------- /lib/rave.base.js: -------------------------------------------------------------------------------- 1 | var q = require('q'); 2 | const querystring = require('querystring'); 3 | var RaveUtils = require('../utils/rave.utils'); 4 | var Security = require('./security'); 5 | 6 | var RaveBase = function (public_key, secret_key, _base_url) { 7 | RaveUtils.emptyCheck(public_key, 'Public Key required'); 8 | RaveUtils.emptyCheck(secret_key, 'Secret Key required'); 9 | 10 | var public_key = public_key; 11 | var secret_key = secret_key; 12 | var base_url = 'https://api.flutterwave.com/'; 13 | 14 | // Override BaseURL 15 | if (_base_url && typeof _base_url === 'string') { 16 | base_url = _base_url; 17 | } 18 | 19 | this.getPublicKey = function () { 20 | return public_key; 21 | }; 22 | 23 | this.getSecretKey = function () { 24 | return secret_key; 25 | }; 26 | 27 | this.getBaseUrl = function () { 28 | return base_url; 29 | }; 30 | 31 | this.setBaseUrl = function (new_base_url) { 32 | if (new_base_url) { 33 | base_url = new_base_url; 34 | } 35 | }; 36 | 37 | this.request = function (path, payload, callback) { 38 | var requestOptions = {}; 39 | var requestMethod = RaveUtils.initDefaultValue( 40 | payload.method, 41 | 'POST' || 'PUT', 42 | ); 43 | var datakey = requestMethod == 'POST' || 'PUT' ? 'body' : 'qs'; 44 | var requestJSON = datakey == 'body' ? true : false; 45 | var includeQueryParams = RaveUtils.initDefaultValue( 46 | payload.excludeQuery, 47 | false, 48 | ); 49 | 50 | // Build URL 51 | let fullUrl = this.getBaseUrl() + path; 52 | 53 | // Prepare request options for fetch 54 | const fetchOptions = { 55 | method: requestMethod, 56 | headers: { 57 | 'Content-Type': 'application/json', 58 | Authorization: `Bearer ${this.getSecretKey()}`, 59 | }, 60 | }; 61 | 62 | // Handle query parameters for GET requests 63 | if (requestMethod === 'GET') { 64 | delete payload.method; 65 | if (!includeQueryParams) { 66 | delete payload.excludeQuery; 67 | const queryParams = querystring.stringify(payload); 68 | if (queryParams) { 69 | fullUrl += fullUrl.includes('?') ? '&' : '?'; 70 | fullUrl += queryParams; 71 | } 72 | } 73 | } else { 74 | // Handle request body for non-GET requests 75 | if (Object.keys(payload).length > 0) { 76 | // Remove method and excludeQuery properties before sending 77 | const payloadCopy = { ...payload }; 78 | delete payloadCopy.method; 79 | delete payloadCopy.excludeQuery; 80 | fetchOptions.body = JSON.stringify(payloadCopy); 81 | } 82 | } 83 | 84 | // Store original options for legacy compatibility 85 | requestOptions.uri = path; 86 | requestOptions.baseUrl = this.getBaseUrl(); 87 | requestOptions.method = requestMethod; 88 | requestOptions[datakey] = RaveUtils.initDefaultValue(payload, {}); 89 | requestOptions.json = requestJSON; 90 | requestOptions.headers = fetchOptions.headers; 91 | 92 | if (callback) { 93 | this._makeRequest(fullUrl, fetchOptions, callback); 94 | return requestOptions; 95 | } else { 96 | return this._makePromiseRequest(fullUrl, fetchOptions); 97 | } 98 | }; 99 | }; 100 | 101 | RaveBase.prototype.encrypt = function (data) { 102 | var encryption_key = Security.getEncryptionKey(this.getSecretKey()); 103 | return Security.encrypt(encryption_key, JSON.stringify(data)); 104 | }; 105 | 106 | RaveBase.prototype.getIntegrityHash = function (data) { 107 | return Security.getIntegrityHash( 108 | data, 109 | this.getPublicKey(), 110 | this.getSecretKey(), 111 | ); 112 | }; 113 | 114 | RaveBase.prototype._makeRequest = function (url, fetchOptions, callback) { 115 | fetch(url, fetchOptions) 116 | .then((response) => { 117 | const res = { 118 | statusCode: response.status, 119 | headers: Object.fromEntries(response.headers.entries()), 120 | }; 121 | 122 | return response 123 | .json() 124 | .then((body) => { 125 | callback(null, res, body); 126 | }) 127 | .catch((err) => { 128 | return response.text().then((textBody) => { 129 | callback(null, res, textBody || {}); 130 | }); 131 | }); 132 | }) 133 | .catch((err) => { 134 | callback(err, {}, {}); 135 | }); 136 | }; 137 | 138 | RaveBase.prototype._makePromiseRequest = function (url, fetchOptions) { 139 | return new Promise((resolve, reject) => { 140 | fetch(url, fetchOptions) 141 | .then((response) => { 142 | const res = { 143 | statusCode: response.status, 144 | headers: Object.fromEntries(response.headers.entries()), 145 | }; 146 | 147 | return response 148 | .json() 149 | .then((body) => { 150 | resolve({ res, body }); 151 | }) 152 | .catch((err) => { 153 | return response.text().then((textBody) => { 154 | resolve({ res, body: textBody || {} }); 155 | }); 156 | }); 157 | }) 158 | .catch((err) => { 159 | reject(err); 160 | }); 161 | }); 162 | }; 163 | 164 | module.exports = RaveBase; 165 | -------------------------------------------------------------------------------- /test/rave.beneficiaries.test.js: -------------------------------------------------------------------------------- 1 | var beneficiaries = require('../lib/rave.beneficiaries'); 2 | var base = require('../lib/rave.base'); 3 | 4 | var Promise = require('bluebird'); 5 | var mocha = require('mocha'); 6 | var chai = require('chai'); 7 | var expect = chai.expect; 8 | var chaiAsPromised = require('chai-as-promised'); 9 | 10 | var dotenv = require('dotenv').config(); 11 | 12 | const sinon = require('sinon'); 13 | const sinonChai = require('sinon-chai'); 14 | 15 | chai.use(chaiAsPromised); 16 | chai.use(sinonChai); 17 | 18 | describe('#Rave Beneficiaries', function () { 19 | const public_key = process.env.PUBLIC_KEY; 20 | const secret_key = process.env.SECRET_KEY; 21 | const ravebase = new base(public_key, secret_key); 22 | 23 | let beneficiariesInstance; 24 | let beneficiariesStub; 25 | 26 | beforeEach(() => { 27 | beneficiariesInstance = new beneficiaries(ravebase); 28 | }); 29 | 30 | afterEach(() => { 31 | sinon.restore(); 32 | }); 33 | 34 | it('should create a Beneficiary', async function () { 35 | this.timeout(10000); 36 | 37 | const createBeneficiariesSuccessStub = sinon 38 | .stub(beneficiariesInstance, 'create') 39 | .resolves({ 40 | body: { 41 | status: 'success', 42 | message: 'Banks fetched successfully', 43 | data: { 44 | id: 3644, 45 | account_number: '0690000034', 46 | bank_code: '044', 47 | full_name: 'Ade Bond', 48 | created_at: '2020-01-16T18:01:28.000Z', 49 | bank_name: 'ACCESS BANK NIGERIA', 50 | }, 51 | }, 52 | }); 53 | 54 | var payload = { 55 | account_number: '0690000034', 56 | account_bank: '044', 57 | beneficiary_name: 'Ade Bond' 58 | }; 59 | 60 | var resp = await beneficiariesInstance.create(payload); 61 | // console.log(resp); 62 | 63 | // success case 64 | expect(createBeneficiariesSuccessStub).to.have.been.calledOnce; 65 | expect(createBeneficiariesSuccessStub).to.have.been.calledOnceWith(payload); 66 | 67 | expect(resp.body).to.have.property('status', 'success'); 68 | expect(resp.body).to.have.property('data'); 69 | 70 | expect(resp.body.data).to.have.property('id'); 71 | expect(resp.body.data).to.have.property('account_number'); 72 | expect(resp.body.data).to.have.property('bank_code'); 73 | expect(resp.body.data).to.have.property('full_name'); 74 | expect(resp.body.data).to.have.property('bank_name'); 75 | }); 76 | 77 | it('should return Account resolve error', async function () { 78 | this.timeout(10000); 79 | 80 | const createBeneficiariesFailedStub = sinon 81 | .stub(beneficiariesInstance, 'create') 82 | .resolves({ 83 | body: { 84 | status: 'error', 85 | message: 'Account resolve failed', 86 | data: null, 87 | }, 88 | }); 89 | 90 | var payload = { 91 | account_number: '0690000034', 92 | account_bank: '044', 93 | }; 94 | 95 | var resp = await beneficiariesInstance.create(payload); 96 | 97 | // failed case 98 | expect(createBeneficiariesFailedStub).to.have.been.calledOnce; 99 | expect(createBeneficiariesFailedStub).to.have.been.calledOnceWith(payload); 100 | 101 | expect(resp.body).to.have.property('status', 'error'); 102 | expect(resp.body.message).to.eq('Account resolve failed'); 103 | }); 104 | 105 | it('should return a single beneficiary ', async function () { 106 | this.timeout(10000); 107 | 108 | const fetchBeneficiariesStub = sinon 109 | .stub(beneficiariesInstance, 'fetch') 110 | .resolves({ 111 | body: { 112 | status: 'success', 113 | message: 'Payout beneficiary fetched', 114 | data: { 115 | id: 2923, 116 | account_number: '0690000032', 117 | bank_code: '044', 118 | full_name: 'Pastor Bright', 119 | meta: null, 120 | created_at: '2019-11-28T08:15:29.000Z', 121 | bank_name: 'ACCESS BANK NIGERIA', 122 | }, 123 | }, 124 | }); 125 | 126 | var payload = { 127 | id: '2923', 128 | }; 129 | 130 | var resp = await beneficiariesInstance.fetch(payload); 131 | 132 | // success case 133 | expect(fetchBeneficiariesStub).to.have.been.calledOnce; 134 | expect(fetchBeneficiariesStub).to.have.been.calledOnceWith(payload); 135 | 136 | expect(resp.body).to.have.property('status', 'success'); 137 | expect(resp.body).to.have.property('data'); 138 | 139 | expect(resp.body.data).to.have.property('id'); 140 | expect(resp.body.data).to.have.property('account_number'); 141 | expect(resp.body.data).to.have.property('bank_code'); 142 | expect(resp.body.data).to.have.property('full_name'); 143 | expect(resp.body.data).to.have.property('bank_name'); 144 | 145 | expect(resp.body.data.id).to.eq(2923); 146 | }); 147 | 148 | it('should successfully delete beneficiary ', async function () { 149 | this.timeout(10000); 150 | 151 | const deleteBeneficiariesStub = sinon 152 | .stub(beneficiariesInstance, 'delete') 153 | .resolves({ 154 | body: { 155 | status: 'success', 156 | message: 'Beneficiary deleted', 157 | data: 'Deleted', 158 | }, 159 | }); 160 | 161 | var payload = { 162 | id: '3644', 163 | }; 164 | 165 | var resp = await beneficiariesInstance.delete(payload); 166 | 167 | expect(deleteBeneficiariesStub).to.have.been.calledOnce; 168 | expect(deleteBeneficiariesStub).to.have.been.calledOnceWith(payload); 169 | 170 | expect(resp.body).to.have.property('status', 'success'); 171 | expect(resp.body.message).to.eq('Beneficiary deleted'); 172 | }); 173 | }); 174 | -------------------------------------------------------------------------------- /documentation/subscription.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # SUBSCRIPTION 6 | 7 | We recommend reading the main readme first, to understand the requirements for using the library and how to initiate this in your apps. This guide assumes you've read that. 8 | 9 | Manage User subscriptions via any of these methods: 10 | 1. [Get all Subscriptions](#get-all-subscriptions) 11 | 2. [Fetch a Subscription](#fetch-subscriptions-with-customers-email) 12 | 3. [Cancel a Subscription](#cancel-a-subscription) 13 | 4. [Activate a Subscription](#activate-a-subscription) 14 | 15 | ## Get all subscriptions 16 | 17 | This describes how to get all subscriptions 18 | 19 | ```javascript 20 | const Flutterwave = require('flutterwave-node-v3'); 21 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 22 | const fetchSubscription = async () => { 23 | 24 | try { 25 | 26 | const response = await flw.Subscription.fetch_all() 27 | console.log(response); 28 | } catch (error) { 29 | console.log(error) 30 | } 31 | 32 | fetchSubscription(); 33 | ``` 34 | 35 | Sample Response 36 | 37 | ```javascript 38 | { 39 | "status": "success", 40 | "message": "Plan subscriptions fetched", 41 | "meta": { 42 | "page_info": { 43 | "total": 2, 44 | "current_page": 1, 45 | "total_pages": 1 46 | } 47 | }, 48 | "data": [ 49 | { 50 | "id": 4147, 51 | "amount": 2000, 52 | "customer": { 53 | "id": 247546, 54 | "customer_email": "developers@flutterwavego.com" 55 | }, 56 | "plan": 3657, 57 | "status": "cancelled", 58 | "created_at": "2019-12-31T17:00:55.000Z" 59 | }, 60 | { 61 | "id": 4146, 62 | "amount": 2000, 63 | "customer": { 64 | "id": 247490, 65 | "customer_email": "developers@flutterwavego.com" 66 | }, 67 | "plan": 3657, 68 | "status": "cancelled", 69 | "created_at": "2019-12-31T14:44:20.000Z" 70 | } 71 | ] 72 | } 73 | ``` 74 | 75 | ## Fetch subscriptions with customer's email 76 | 77 | This describes how to fetch subscriptions made by a single user. 78 | 79 | ```javascript 80 | const Flutterwave = require('flutterwave-node-v3'); 81 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 82 | const getSubscription = async () => { 83 | 84 | try { 85 | const data = { 86 | "email": "cornelius@flutterwavego.com" 87 | } 88 | const response = await flw.Subscription.get(data) 89 | console.log(response); 90 | } catch (error) { 91 | console.log(error) 92 | } 93 | } 94 | getSubscription(); 95 | ``` 96 | 97 | Sample Response 98 | 99 | ```javascript 100 | { 101 | "status": "success", 102 | "message": "Plan subscriptions fetched", 103 | "meta": { 104 | "page_info": { 105 | "total": 1, 106 | "current_page": 1, 107 | "total_pages": 1 108 | } 109 | }, 110 | "data": [ 111 | { 112 | "id": 15376, 113 | "amount": 2000, 114 | "customer": { 115 | "id": 1500129, 116 | "customer_email": "cornelius@flutterwavego.com" 117 | }, 118 | "plan": 17490, 119 | "status": "cancelled", 120 | "created_at": "2022-01-24T15:05:45.000Z" 121 | } 122 | ] 123 | } 124 | ``` 125 | 126 | 127 | ## Cancel a subscription 128 | 129 | This describes how to cancel a subscription 130 | 131 | ```javascript 132 | const Flutterwave = require('flutterwave-node-v3'); 133 | 134 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 135 | 136 | const cancelSubscription = async () => { 137 | 138 | try { 139 | const payload={ 140 | "id":"4147" //This is the unique id of the subscription you want to cancel. It is returned in the Get a subscription call as data.id 141 | } 142 | 143 | const response = await flw.Subscription.cancel(payload) 144 | console.log(response); 145 | } catch (error) { 146 | console.log(error) 147 | } 148 | 149 | } 150 | 151 | cancelSubscription(); 152 | ``` 153 | 154 | Sample Response 155 | 156 | ```javascript 157 | { 158 | "status": "success", 159 | "message": "Subscription cancelled", 160 | "data": { 161 | "id": 4147, 162 | "amount": 2000, 163 | "customer": { 164 | "id": 247546, 165 | "customer_email": "developers@flutterwavego.com" 166 | }, 167 | "plan": 3657, 168 | "status": "cancelled", 169 | "created_at": "2019-12-31T17:00:55.000Z" 170 | } 171 | } 172 | ``` 173 | 174 | ## Activate a subscription 175 | 176 | This describes how to activate a subscription 177 | 178 | ```javascript 179 | const Flutterwave = require('flutterwave-node-v3'); 180 | 181 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 182 | 183 | const activateSubscription = async () => { 184 | 185 | try { 186 | const payload={ 187 | "id":"4147" //This is the unique id of the subscription you want to activate. It is returned in the Get a subscription call as data.id 188 | } 189 | 190 | const response = await flw.Subscription.activate(payload) 191 | console.log(response); 192 | } catch (error) { 193 | console.log(error) 194 | } 195 | 196 | } 197 | 198 | activateSubscription(); 199 | ``` 200 | 201 | Sample Response 202 | 203 | ```javascript 204 | { 205 | "status": "success", 206 | "message": "Subscription activated", 207 | "data": { 208 | "id": 4147, 209 | "amount": 2000, 210 | "customer": { 211 | "id": 247546, 212 | "customer_email": "developers@flutterwavego.com" 213 | }, 214 | "plan": 3657, 215 | "status": "active", 216 | "created_at": "2019-12-31T17:00:55.000Z" 217 | } 218 | } 219 | 220 | ``` 221 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## 1.3.0 | 2025-04-17 3 | 4 | Remove SDK logger 5 | 6 | ### Version Changes 7 | 8 | - [REMOVED] logger tracking errors in the integration libraries. 9 | 10 | 11 | ## 1.2.1 | 2025-04-14 12 | 13 | Added validation for mobile money networks. 14 | 15 | ### Version Changes 16 | 17 | - [ADDED] `network` validations for mobilemoney collections in the momoSchema. 18 | - [ADDED] checkmarx security scan to the package build pipeline. 19 | 20 | ## 1.2.0 | 2025-04-09 21 | 22 | Replace `Request` package with `Fetch` for HTTP requests and update the charge schema. 23 | 24 | ### Version Changes 25 | 26 | - [ADDED] `sa_bank_code` in the chargeSchema. 27 | - [ADDED] Fetch API to handle HTTP calls in the SDK. 28 | - [FIXED] Bumped axios version to the latest. 29 | - [REMOVED] The deprecated request package as a dependency. 30 | 31 | ## 1.1.15 | 2025-02-28 32 | 33 | Added transaction verification by reference and updated the settlement imports for the `fetch_all()` and `fetch()` settlement methods. 34 | 35 | ### Version Changes 36 | 37 | - [ADDED] Transaction verification by reference(`tx_ref`). 38 | - [FIXED] Update the `fetch_all()` and `fetch()` settlement methods to use the correct settlement imports, ensuring they send the correct requests to the Flutterwave API. 39 | 40 | ## 1.1.14 | 2024-12-13 41 | 42 | Updated the `voucher` parameter in the momo schema. 43 | 44 | ### Version Changes 45 | 46 | - [FIXED] Make the `voucher` parameter optional in the create mobile money schema. 47 | 48 | ## 1.1.13 | 2024-11-19 49 | 50 | Updated the `getBalanceByCurrency` method to parse path parameters. 51 | 52 | ### Version Changes 53 | 54 | - [FIXED] Update the `balance_currency` function in the Misc object to exclude queries when parsing a path parameter. 55 | 56 | ## 1.1.12 | 2024-09-27 57 | 58 | Update the list schema. 59 | 60 | ### Version Changes 61 | 62 | - [FIXED] Remove the required validation on the 'account_bank' parameter. 63 | 64 | ## 1.1.11 | 2024-09-10 65 | 66 | Update `account_bank` validation in create schema. 67 | 68 | ### Version Changes 69 | 70 | - [FIXED] Update minLength & maxLength validation for account_bank parameter. 71 | 72 | ## 1.1.10 | 2024-04-04 73 | 74 | Updated the variable name "package" which happens to be a reserved word in JavaScript, and it is causing compatibility issues with certain bundlers. 75 | 76 | ### Version Changes 77 | 78 | - [FIXED] changed the variable name 'package' to 'packageJson' in the logger.js file. 79 | 80 | ## 1.1.9 | 2024-03-18 81 | 82 | Validation hotfix on subaccounts 83 | 84 | ### Version Changes. 85 | 86 | - [FIXED] Update validation (minLength & maxLength) for 'account_bank" parameter in the subaccountSchema. 87 | 88 | ## 1.1.8 | 2024-02-19 89 | 90 | Updated BVN verification flow and hotfixes on subaccount, bills and transaction fees: 91 | 92 | ### Version Changes. 93 | 94 | - [ADDED] New BVN verification flow (via NIBBS). 95 | - [ADDED] Unit tests for more coverage on the BVN verification, fees, and split payments. 96 | - [ADDED] Subaccounts parameter (optional) to card charge and PWBT requests. 97 | - [FIXED] Resolved "URL Not Found" Error returned from Validate Bill Service method. 98 | - [FIXED] Resolved "Invalid currency provided" Error returned from the Transaction fees method. 99 | 100 | ## 1.1.7 | 2024-01-25 101 | 102 | Scheduled updates and bugfixes: 103 | 104 | ### Version Changes. 105 | 106 | - [ADDED] Tanzania mobile money payment method. 107 | - [ADDED] Fawry Pay payment method. 108 | - [ADDED] Supplementary parameters in the createBulkTransferSchema. 109 | - [ADDED] Expires parameter (optional) to PWBT (Pay with Bank Transfer) requests. 110 | - [ADDED] Schema for USSD charge (ussdChargeSchema). 111 | - [ADDED] Status parameter to the updatePlanSchema requests. 112 | - [ADDED] Unit tests for more coverage on Fawry Pay, Google Pay, Apple Pay, and eNaira 113 | - [ADDED] Unit tests for more coverage on payment plans, Charge NG Bank Account (Mono), Charge with Bank Transfer (PWBT), and Change UK & EU Bank Account. 114 | - [FIXED] Optional parameters in beneficiarySchema. 115 | - [FIXED] Updated transaction tests to stub response. 116 | - [FIXED] Modified "id" in the fetchSchema to accept only integer values. 117 | - [FIXED] Support string values for zip code in the cardChargeSchema. 118 | - [FIXED] Support string values for "billing_zip" in the chargeSchema. 119 | - [FIXED] Extended the length of "account_bank" values in the transferSchema. 120 | - [FIXED] Updated the UK & USSD bank charge. 121 | - [FIXED] Revised the NG bank charge (Mono). 122 | - [REMOVED] Eliminated the "amount" parameter in the updatePlanSchema. 123 | 124 | ## 1.1.6 | 2023-06-21 125 | 126 | Hotfix on Transfer fees and Bank lists. 127 | 128 | ### Version changes. 129 | 130 | - [FIXED] Transfer fees returning 0 for all amounts. 131 | - [FIXED] Null data response for Bank lists. 132 | 133 | ## 1.1.5 | 2023-04-13 134 | 135 | Hotfix to hide header information in the library response. 136 | 137 | ### Version changes. 138 | 139 | - [FIXED] Removed headers in the response. 140 | 141 | ## 1.1.4 | 2023-04-13 142 | 143 | This release fixes the empty subscription fetch query with user email. 144 | 145 | ### Version changes. 146 | 147 | - [FIXED] Empty data in response object for subscription fetch with email query parameter 148 | 149 | ## 1.1.3 | 2023-03-29 150 | 151 | Scheduled updates and bug fixes. This release fixes all the bugs in the new SDK (v1.1.0) 152 | 153 | ### Version changes. 154 | 155 | - [FIXED] Updated validation for empty meta objects in charge and transfer methods. 156 | - [FIXED] Added conditional validation for `Country`, `Network`and `Voucher` parameters in Mobile Money schema. 157 | - [FIXED] [#111](https://github.com/Flutterwave/Node/issues/111) Verify transaction error. 158 | - [FIXED] Title validation in Card issuing schema. 159 | - [FIXED] Import errors in Virtual account methods. 160 | - [ADDED] Support for query parameters in listing methods. 161 | - [REMOVED] Replaced `first_name` and `last_name` in the Card tokenization schema with a single `full_name`field. 162 | 163 | ## 1.1.1 | 2023-03-17 164 | 165 | This release fixes all morx errors thrown in custom request class. 166 | 167 | ### Version changes. 168 | 169 | - [FIXED] Morx error returned in custom service class in v1.1.0 170 | 171 | ## 1.1.0 | 2023-03-14 172 | 173 | This release fixes all npm warnings and dependabot error messages. 174 | 175 | ### Version changes. 176 | 177 | - [FIXED] [#103](https://github.com/Flutterwave/Node/issues/103) Multiple Vulnerabilities Introduced by dependencies 178 | - [FIXED] [#87](https://github.com/Flutterwave/Node/issues/87) Amount is required for payment plan creation 179 | - [FIXED] [#84](https://github.com/Flutterwave/Node/issues/84) Cannot filter bills by category 180 | - [FIXED] [#79](https://github.com/Flutterwave/Node/issues/79) Urgent: Transactions GET endpoint or any endpoints with qs doesn't work 181 | - [ADDED] Support for ApplePay, GooglePay and eNaira payments. 182 | -------------------------------------------------------------------------------- /documentation/misc.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # MISC 6 | 7 | We recommend reading the main readme first, to understand the requirements for using the library and how to initiate this in your apps. This guide assumes you've read that. 8 | 9 | Verify user information via any of these methods: 10 | 1. [Get all wallet balances](#get-all-wallet-balances) 11 | 2. [Get Balances per Currency](#get-balances-per-currency) 12 | 3. [Resolve Account Details](#resolve-account-details) 13 | 4. [Resolve BVN Details](#resolve-bvn-details) 14 | 15 | 16 | ## Get all wallet balances 17 | 18 | This describes how to get all wallet balances 19 | 20 | ```javascript 21 | const Flutterwave = require('flutterwave-node-v3'); 22 | 23 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 24 | 25 | 26 | const fetchBal = async () => { 27 | 28 | try { 29 | 30 | const response = await flw.Misc.bal() 31 | console.log(response); 32 | } catch (error) { 33 | console.log(error) 34 | } 35 | 36 | } 37 | 38 | 39 | fetchBal(); 40 | 1 41 | ``` 42 | 43 | Sample Response 44 | 45 | ```javascript 46 | { 47 | "status": "success", 48 | "message": "Wallet balances fetched", 49 | "data": [ 50 | { 51 | "currency": "NGN", 52 | "available_balance": 2367840, 53 | "ledger_balance": 253125.82 54 | }, 55 | { 56 | "currency": "KES", 57 | "available_balance": 0, 58 | "ledger_balance": 1226.72 59 | }, 60 | { 61 | "currency": "GHS", 62 | "available_balance": 0, 63 | "ledger_balance": 0 64 | }, 65 | { 66 | "currency": "USD", 67 | "available_balance": 0, 68 | "ledger_balance": 472.08 69 | }, 70 | { 71 | "currency": "EUR", 72 | "available_balance": 0, 73 | "ledger_balance": 0 74 | }, 75 | { 76 | "currency": "ZAR", 77 | "available_balance": 0, 78 | "ledger_balance": 0 79 | }, 80 | { 81 | "currency": "GBP", 82 | "available_balance": 0, 83 | "ledger_balance": 0 84 | }, 85 | { 86 | "currency": "TZS", 87 | "available_balance": 0, 88 | "ledger_balance": 0 89 | }, 90 | { 91 | "currency": "UGX", 92 | "available_balance": 0, 93 | "ledger_balance": 0 94 | }, 95 | { 96 | "currency": "RWF", 97 | "available_balance": 0, 98 | "ledger_balance": 5000 99 | }, 100 | { 101 | "currency": "ZMW", 102 | "available_balance": 0, 103 | "ledger_balance": 0 104 | }, 105 | { 106 | "currency": "INR", 107 | "available_balance": 0, 108 | "ledger_balance": 0 109 | }, 110 | { 111 | "currency": "XOF", 112 | "available_balance": 0, 113 | "ledger_balance": 0 114 | }, 115 | { 116 | "currency": "MUR", 117 | "available_balance": 0, 118 | "ledger_balance": 0 119 | }, 120 | { 121 | "currency": "ETB", 122 | "available_balance": 0, 123 | "ledger_balance": 0 124 | } 125 | ] 126 | } 127 | ``` 128 | 129 | ## Get balances per currency 130 | 131 | This describes how to get balances for specific currencies 132 | 133 | ```javascript 134 | 135 | const Flutterwave = require('flutterwave-node-v3'); 136 | 137 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 138 | 139 | 140 | const fetchBal = async () => { 141 | 142 | try { 143 | const payload = { 144 | "currency": "NGN", 145 | } 146 | const response = await flw.Misc.bal_currency(payload) 147 | console.log(response); 148 | } catch (error) { 149 | console.log(error) 150 | } 151 | 152 | } 153 | 154 | 155 | fetchBal(); 156 | ``` 157 | 158 | Sample Response 159 | 160 | ```javascript 161 | { 162 | "status": "success", 163 | "message": "Wallet balance fetched", 164 | "data": { 165 | "currency": "NGN", 166 | "available_balance": 2168880, 167 | "ledger_balance": 253125.82 168 | } 169 | } 170 | ``` 171 | 172 | ## Resolve account details 173 | 174 | This describes how to resolve a bank account to get the account holder's details 175 | 176 | ```javascript 177 | 178 | const Flutterwave = require('flutterwave-node-v3'); 179 | 180 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 181 | 182 | 183 | const resolveAcct = async () => { 184 | 185 | try { 186 | const payload = { 187 | "account_number": "0690000032", 188 | "account_bank": "044" 189 | } 190 | const response = await flw.Misc.verify_Account(payload) 191 | console.log(response); 192 | } catch (error) { 193 | console.log(error) 194 | } 195 | 196 | } 197 | 198 | 199 | resolveAcct(); 200 | ``` 201 | 202 | Sample Response 203 | 204 | ```javascript 205 | { 206 | "status": "success", 207 | "message": "Account details fetched", 208 | "data": { 209 | "account_number": "0690000032", 210 | "account_name": "Pastor Bright" 211 | } 212 | } 213 | ``` 214 | 215 | ## Initiate BVN Consent 216 | 217 | This describes how to initiate bvn consent flow for your customer. 218 | 219 | ```javascript 220 | const Flutterwave = require('flutterwave-node-v3'); 221 | 222 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 223 | 224 | 225 | 226 | const initiateBvn = async () => { 227 | 228 | try { 229 | const payload = { 230 | "bvn": "12347832211", 231 | "firstname": "Lyra", 232 | "lastname:" "Balacqua", 233 | "redirect_url": "https://example-url.company.com" 234 | } 235 | const response = await flw.Misc.bvn(payload) 236 | console.log(response); 237 | } catch (error) { 238 | console.log(error) 239 | } 240 | 241 | } 242 | 243 | 244 | initiateBvn(); 245 | ``` 246 | 247 | Sample Response 248 | 249 | ```javascript 250 | { 251 | "status":"success", 252 | "message":"Bvn verification initiated", 253 | "data":{ 254 | "url":"https://nibss-bvn-consent-management.dev-flutterwave.com/cms/BvnConsent?session=MWNkNDI4ZWYtMjgwNy00ZjA1LWE5NzUtNzUyZGUyZDRjZWQz", 255 | "reference":"FLW71DC60942BAD76D2BD5B4E" 256 | } 257 | } 258 | ``` 259 | 260 | ## Verify BVN consent 261 | 262 | This describes how to Verify consent and retirve the customer's BVN information. 263 | 264 | ```javascript 265 | const Flutterwave = require('flutterwave-node-v3'); 266 | 267 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 268 | 269 | 270 | 271 | const verifyBvn = async () => { 272 | 273 | try { 274 | const payload = { 275 | "reference":"FLW71DC60942BAD76D2BD5B4E" 276 | } 277 | const response = await flw.Misc.verifybvn(payload) 278 | console.log(response); 279 | } catch (error) { 280 | console.log(error) 281 | } 282 | 283 | } 284 | 285 | 286 | verifyBVN(); 287 | ``` 288 | 289 | Sample Response 290 | 291 | ```javascript 292 | { 293 | "status":"success", 294 | "message":"Bvn details fetched", 295 | "data":{ 296 | "first_name":"Lyra", 297 | "last_name":"Balacqua", 298 | "status":"INITIATED", 299 | "reference":"FLW71DC60942BAD76D2BD5B4E", 300 | "callback_url":null, 301 | "bvn_data":null, 302 | "created_at":"2024-02-16T08:28:10.000Z" 303 | } 304 | } 305 | ``` 306 | 307 | -------------------------------------------------------------------------------- /documentation/beneficiary.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # BENEFICIARIES 6 | 7 | We recommend reading the main readme first, to understand the requirements for using the library and how to initiate this in your apps. This guide assumes you've read that. 8 | 9 | Manage transfer beneficiaries via any of these methods: 10 | 1. [Create a Beneficiary](#create-a-beneficiary) 11 | 2. [Delete a Beneficiary](#delete-a-beneficiary) 12 | 3. [Fetch a Beneficiary](#fetch-a-beneficiary) 13 | 4. [Fetch all Beneficiaries](#list-all-beneficiaries) 14 | 15 | 16 | ## Create a beneficiary 17 | 18 | This describes how to create a transfer beneficiary 19 | 20 | ```javascript 21 | 22 | const Flutterwave = require('flutterwave-node-v3'); 23 | 24 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 25 | 26 | const createBeneficiary = async () => { 27 | 28 | try { 29 | const payload = { 30 | "account_number": "0690000034", 31 | "account_bank":"044" // This is the beneficiary’s bank code, you can use the List of Banks to retrieve a bank code. 32 | "beneficiary_name": 'Ade Bond' 33 | } 34 | const response = await flw.Beneficiary.create(payload) 35 | console.log(response); 36 | } catch (error) { 37 | console.log(error) 38 | } 39 | 40 | } 41 | 42 | 43 | createBeneficiary(); 44 | ``` 45 | 46 | Sample Response 47 | 48 | ```javascript 49 | { 50 | "status": "success", 51 | "message": "Banks fetched successfully", 52 | "data": { 53 | "id": 3644, 54 | "account_number": "0690000034", 55 | "bank_code": "044", 56 | "full_name": "Ade Bond", 57 | "created_at": "2020-01-16T18:01:28.000Z", 58 | "bank_name": "ACCESS BANK NIGERIA" 59 | } 60 | } 61 | ``` 62 | 63 | ## List all beneficiaries 64 | 65 | This describes how to get all beneficiaries 66 | 67 | ```javascript 68 | const Flutterwave = require('flutterwave-node-v3'); 69 | 70 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 71 | 72 | 73 | const fetchAllBeneficiary = async () => { 74 | 75 | try { 76 | 77 | const response = await flw.Beneficiary.fetch_all() 78 | console.log(response); 79 | } catch (error) { 80 | console.log(error) 81 | } 82 | 83 | } 84 | 85 | 86 | fetchAllBeneficiary(); 87 | ``` 88 | 89 | Sample Response 90 | 91 | ```javascript 92 | { 93 | "status": "success", 94 | "message": "Payout beneficiaries fetched", 95 | "meta": { 96 | "page_info": { 97 | "total": 9, 98 | "current_page": 1, 99 | "total_pages": 1 100 | } 101 | }, 102 | "data": [ 103 | { 104 | "id": 3768, 105 | "account_number": "0690000040", 106 | "bank_code": "044", 107 | "full_name": "Alexis Sanchez", 108 | "meta": null, 109 | "created_at": "2020-01-20T16:09:24.000Z", 110 | "bank_name": "ACCESS BANK NIGERIA" 111 | }, 112 | { 113 | "id": 3690, 114 | "account_number": "0690000039", 115 | "bank_code": "044", 116 | "full_name": "Dotun Ajib", 117 | "meta": null, 118 | "created_at": "2020-01-19T22:36:06.000Z", 119 | "bank_name": "ACCESS BANK NIGERIA" 120 | }, 121 | { 122 | "id": 3644, 123 | "account_number": "0690000034", 124 | "bank_code": "044", 125 | "full_name": "Ade Bond", 126 | "meta": null, 127 | "created_at": "2020-01-16T18:01:28.000Z", 128 | "bank_name": "ACCESS BANK NIGERIA" 129 | }, 130 | { 131 | "id": 3608, 132 | "account_number": "0690000044", 133 | "bank_code": "044", 134 | "full_name": "Mercedes Daniel", 135 | "meta": null, 136 | "created_at": "2020-01-15T11:58:02.000Z", 137 | "bank_name": "ACCESS BANK NIGERIA" 138 | }, 139 | { 140 | "id": 3565, 141 | "account_number": "0690000038", 142 | "bank_code": "044", 143 | "full_name": "John Sunday", 144 | "meta": null, 145 | "created_at": "2020-01-14T05:53:34.000Z", 146 | "bank_name": "ACCESS BANK NIGERIA" 147 | }, 148 | { 149 | "id": 3104, 150 | "account_number": "2540782773934", 151 | "bank_code": "000", 152 | "full_name": "Kwame Adew", 153 | "meta": null, 154 | "created_at": "2019-12-05T23:49:31.000Z", 155 | "bank_name": "FA-BANK" 156 | }, 157 | { 158 | "id": 3093, 159 | "account_number": "0690000041", 160 | "bank_code": "044", 161 | "full_name": "Alexis Rogers", 162 | "meta": null, 163 | "created_at": "2019-12-05T21:29:57.000Z", 164 | "bank_name": "ACCESS BANK NIGERIA" 165 | }, 166 | { 167 | "id": 2923, 168 | "account_number": "0690000032", 169 | "bank_code": "044", 170 | "full_name": "Pastor Bright", 171 | "meta": null, 172 | "created_at": "2019-11-28T08:15:29.000Z", 173 | "bank_name": "ACCESS BANK NIGERIA" 174 | }, 175 | { 176 | "id": 2857, 177 | "account_number": "0690000031", 178 | "bank_code": "044", 179 | "full_name": "Forrest Green", 180 | "meta": null, 181 | "created_at": "2019-11-20T10:33:20.000Z", 182 | "bank_name": "ACCESS BANK NIGERIA" 183 | } 184 | ] 185 | } 186 | ``` 187 | 188 | 189 | ## Fetch a beneficiary 190 | 191 | This describes how to get a single transfer beneficiary details 192 | 193 | ```javascript 194 | const Flutterwave = require('flutterwave-node-v3'); 195 | 196 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 197 | 198 | 199 | 200 | const fetchBeneficiary = async () => { 201 | 202 | try { 203 | const payload = { 204 | 205 | "id":"2923" //This is the unique identifier for the beneficiary you intend to fetch. It is returned in the call to create a beneficiary as data.id 206 | 207 | } 208 | const response = await flw.Beneficiary.fetch(payload) 209 | console.log(response); 210 | } catch (error) { 211 | console.log(error) 212 | } 213 | 214 | } 215 | 216 | 217 | fetchBeneficiary(); 218 | ``` 219 | 220 | Sample Response 221 | 222 | ```javascript 223 | { 224 | "status": "success", 225 | "message": "Payout beneficiary fetched", 226 | "data": { 227 | "id": 2923, 228 | "account_number": "0690000032", 229 | "bank_code": "044", 230 | "full_name": "Pastor Bright", 231 | "meta": null, 232 | "created_at": "2019-11-28T08:15:29.000Z", 233 | "bank_name": "ACCESS BANK NIGERIA" 234 | } 235 | } 236 | ``` 237 | 238 | ## Delete a beneficiary 239 | 240 | This describes how to delete a transfer beneficiary 241 | 242 | 243 | ```javascript 244 | const Flutterwave = require('flutterwave-node-v3'); 245 | 246 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 247 | 248 | 249 | const delBeneficiary = async () => { 250 | 251 | try { 252 | const payload = { 253 | 254 | "id":"4150" //This is the unique identifier for the beneficiary you intend to fetch. It is returned in the call to create a beneficiary as data.id 255 | 256 | } 257 | const response = await flw.Beneficiary.delete(payload) 258 | console.log(response); 259 | } catch (error) { 260 | console.log(error) 261 | } 262 | 263 | } 264 | 265 | 266 | delBeneficiary(); 267 | ``` 268 | 269 | Sample Response 270 | 271 | ```javascript 272 | { 273 | "status": "success", 274 | "message": "Beneficiary deleted", 275 | "data": "Deleted" 276 | } 277 | ``` 278 | 279 | -------------------------------------------------------------------------------- /documentation/virtualAccount.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # VIRTUAL ACCOUNT NUMBERS 6 | 7 | We recommend reading the main readme first, to understand the requirements for using the library and how to initiate this in your apps. This guide assumes you've read that. 8 | 9 | Manage Virtual Accounts via any of these methods: 10 | 1. [Create a virtual account number](#create-a-virtual-account-number) 11 | 2. [Create bulk virtual account numbers](#create-bulk-virtual-account-numbers) 12 | 3. [Fetch a virtual account number](#get-a-virtual-account-number) 13 | 4. [Fetch bulk virtual account details](#get-bulk-virtual-account-details) 14 | 15 | 16 | ## Create a virtual account number 17 | 18 | This describes how to create a virtual account number 19 | 20 | Note: BVN is required for creating static account numbers in the Live Environment i.e if the value of is_permanent is True. 21 | Kindly visit our API section found [here](https://developer.flutterwave.com/reference#create-a-virtual-account-number-1) for more information. 22 | 23 | ```javascript 24 | const Flutterwave = require('flutterwave-node-v3'); 25 | 26 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 27 | 28 | const createAcct = async () => { 29 | 30 | try { 31 | const payload = { 32 | "email": "developers@flutterwavego.com", 33 | "is_permanent": true, 34 | "bvn": "12345678901", 35 | "tx_ref": "VA12", 36 | "phonenumber": "08109328188", 37 | "firstname": "Angela", 38 | "lastname": "Ashley", 39 | "narration": "Angela Ashley-Osuzoka" 40 | } 41 | const response = await flw.VirtualAcct.create(payload) 42 | console.log(response); 43 | } catch (error) { 44 | console.log(error) 45 | } 46 | 47 | } 48 | 49 | 50 | createAcct(); 51 | ``` 52 | 53 | Sample Response 54 | 55 | ```javascript 56 | { 57 | "status": "success", 58 | "message": "Virtual account created", 59 | "data": { 60 | "response_code": "02", 61 | "response_message": "Transaction in progress", 62 | "flw_ref": "FLW-da93010f630240a7978e893af92fed62", 63 | "order_ref": "URF_1613406439309_370935", 64 | "account_number": "7824822527", 65 | "frequency": "N/A", 66 | "bank_name": "WEMA BANK", 67 | "created_at": "2021-02-15 16:27:22", 68 | "expiry_date": "N/A", 69 | "note": "Please make a bank transfer to CollinX Akpevwe Omokri", 70 | "amount": null 71 | } 72 | } 73 | ``` 74 | 75 | ## Create bulk virtual account numbers 76 | 77 | This describes how to create bulk virtual account numbers 78 | 79 | ```javascript 80 | const Flutterwave = require('flutterwave-node-v3'); 81 | 82 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 83 | 84 | 85 | const createBulkAcct = async () => { 86 | 87 | try { 88 | const payload = { 89 | "accounts": 5, //This is the number of virtual account numbers you want to generate 90 | "email": "sam@son.com", 91 | "is_permanent": true, 92 | "tx_ref": "jhn-mndkn-012439283422", 93 | "bvn": "12345678901" 94 | } 95 | const response = await flw.VirtualAcct.create_bulk(payload) 96 | console.log(response); 97 | } catch (error) { 98 | console.log(error) 99 | } 100 | 101 | } 102 | 103 | 104 | createBulkAcct(); 105 | ``` 106 | 107 | Sample Response 108 | 109 | ```javascript 110 | { 111 | "status": "success", 112 | "message": "Bulk virtual accounts creation queued", 113 | "data": { 114 | "batch_id": "-RND_2611692003353987", 115 | "response_code": "02", 116 | "response_message": "Request added to Queue" 117 | } 118 | } 119 | ``` 120 | 121 | 122 | ## Get bulk virtual account details 123 | 124 | This describes how to fetch bulk virtual account numbers using batch id 125 | 126 | ```javascript 127 | const Flutterwave = require('flutterwave-node-v3'); 128 | 129 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 130 | 131 | 132 | const fetchBulk = async () => { 133 | 134 | try { 135 | const payload = { 136 | "batch_id": "-RND_1311590351499953", // This is the batch ID returned in the bulk virtual account numbers creation 137 | } 138 | const response = await flw.VirtualAcct.fetch_bulk(payload) 139 | console.log(response); 140 | } catch (error) { 141 | console.log(error) 142 | } 143 | 144 | } 145 | 146 | 147 | fetchBulk(); 148 | ``` 149 | 150 | Sample Response 151 | 152 | ```javascript 153 | { 154 | "status": "success", 155 | "message": "Bulk virtual accounts fetched", 156 | "data": [ 157 | { 158 | "response_code": "02", 159 | "response_message": "Transaction in progress", 160 | "flw_ref": "FLW-f2be3dfeb4fb4f1eb95c236b3129ef0c", 161 | "order_ref": "URF_1579516057896_3120635", 162 | "account_number": "7827737349", 163 | "frequency": "N/A", 164 | "bank_name": "WEMA BANK", 165 | "created_at": "2020-01-20 10:27:38", 166 | "expiry_date": "N/A", 167 | "note": "Please make a bank transfer to Earth Gang", 168 | "amount": null 169 | }, 170 | { 171 | "response_code": "02", 172 | "response_message": "Transaction in progress", 173 | "flw_ref": "FLW-6117c6e877e34f7e80b76268ce73bb69", 174 | "order_ref": "URF_1579516058932_17235", 175 | "account_number": "7827554918", 176 | "frequency": "N/A", 177 | "bank_name": "WEMA BANK", 178 | "created_at": "2020-01-20 10:27:39", 179 | "expiry_date": "N/A", 180 | "note": "Please make a bank transfer to Earth Gang", 181 | "amount": null 182 | }, 183 | { 184 | "response_code": "02", 185 | "response_message": "Transaction in progress", 186 | "flw_ref": "FLW-590fb41034b24dcd9f822f2c02c3cf98", 187 | "order_ref": "URF_1579516059900_4435935", 188 | "account_number": "7827619600", 189 | "frequency": "N/A", 190 | "bank_name": "WEMA BANK", 191 | "created_at": "2020-01-20 10:27:40", 192 | "expiry_date": "N/A", 193 | "note": "Please make a bank transfer to Earth Gang", 194 | "amount": null 195 | }, 196 | { 197 | "response_code": "02", 198 | "response_message": "Transaction in progress", 199 | "flw_ref": "FLW-8e3fb79bb27040d69da1dbe467da8e7c", 200 | "order_ref": "URF_1579516060920_1225335", 201 | "account_number": "7827266267", 202 | "frequency": "N/A", 203 | "bank_name": "WEMA BANK", 204 | "created_at": "2020-01-20 10:27:41", 205 | "expiry_date": "N/A", 206 | "note": "Please make a bank transfer to Earth Gang", 207 | "amount": null 208 | }, 209 | { 210 | "response_code": "02", 211 | "response_message": "Transaction in progress", 212 | "flw_ref": "FLW-1a5264671801416ba09211d0142f0bd1", 213 | "order_ref": "URF_1579516061920_4339335", 214 | "account_number": "7827342397", 215 | "frequency": "N/A", 216 | "bank_name": "WEMA BANK", 217 | "created_at": "2020-01-20 10:27:42", 218 | "expiry_date": "N/A", 219 | "note": "Please make a bank transfer to Earth Gang", 220 | "amount": null 221 | } 222 | ] 223 | } 224 | ``` 225 | 226 | ## Get a virtual account number 227 | 228 | This describes how to fetch a virtual account number using order reference 229 | 230 | ```javascript 231 | const Flutterwave = require('flutterwave-node-v3'); 232 | 233 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 234 | 235 | 236 | const fetch = async () => { 237 | 238 | try { 239 | const payload = { 240 | "order_ref": "URF_1579513580629_5981535", // This is the order reference returned in the virtual account number creation 241 | } 242 | const response = await flw.VirtualAcct.fetch(payload) 243 | console.log(response); 244 | } catch (error) { 245 | console.log(error) 246 | } 247 | 248 | } 249 | 250 | 251 | fetch(); 252 | ``` 253 | 254 | Sample Response 255 | 256 | ```javascript 257 | { 258 | "status": "success", 259 | "message": "Virtual nuban fetched", 260 | "data": { 261 | "response_code": "02", 262 | "response_message": "Transaction in progress", 263 | "flw_ref": "FLW-9b04c88aaf2244379f256691836fd9c9", 264 | "order_ref": "URF_1579513580629_5981535", 265 | "account_number": "7826463244", 266 | "frequency": "5", 267 | "bank_name": "WEMA BANK", 268 | "created_at": "2020-01-20 09:46:23", 269 | "expiry_date": "2020-01-25 23:59:59", 270 | "note": "Please make a bank transfer to Earth Gang", 271 | "amount": 50700 272 | } 273 | } 274 | ``` 275 | 276 | -------------------------------------------------------------------------------- /test/rave.transactions.test.js: -------------------------------------------------------------------------------- 1 | var transactions = require('../lib/rave.transactions'); 2 | var base = require('../lib/rave.base'); 3 | 4 | var Promise = require('bluebird'); 5 | var mocha = require('mocha'); 6 | var chai = require('chai'); 7 | var expect = chai.expect; 8 | var chaiAsPromised = require('chai-as-promised'); 9 | 10 | var dotenv = require('dotenv').config(); 11 | 12 | const sinon = require('sinon'); 13 | const sinonChai = require('sinon-chai'); 14 | 15 | chai.use(chaiAsPromised); 16 | chai.use(sinonChai); 17 | 18 | describe('#Rave Transactions', function () { 19 | const public_key = process.env.PUBLIC_KEY; 20 | const secret_key = process.env.SECRET_KEY; 21 | const ravebase = new base(public_key, secret_key); 22 | 23 | let trxInstance; 24 | // let momoStub; 25 | 26 | beforeEach(() => { 27 | trxInstance = new transactions(ravebase); 28 | }); 29 | 30 | afterEach(() => { 31 | sinon.restore(); 32 | }); 33 | 34 | it('should successfully verify a payment', async function () { 35 | this.timeout(10000); 36 | 37 | const verifyTransactionStub = sinon 38 | .stub(trxInstance, 'verify') 39 | .resolves({ 40 | status: 'success', 41 | message: 'Transaction fetched successfully', 42 | data: { 43 | id: 4186265, 44 | tx_ref: '64020445daeec1677853765', 45 | flw_ref: '5014276956431677853766795', 46 | device_fingerprint: 'N/A', 47 | amount: 2000, 48 | currency: 'NGN', 49 | charged_amount: 2000, 50 | app_fee: 28, 51 | merchant_fee: 0, 52 | processor_response: 'success', 53 | auth_model: 'AUTH', 54 | ip: '52.209.154.143', 55 | narration: 'Flutterwave Developers', 56 | status: 'successful', 57 | payment_type: 'bank_transfer', 58 | created_at: '2023-03-03T14:29:33.000Z', 59 | account_id: 20937, 60 | meta: { 61 | originatoraccountnumber: '123*******90', 62 | originatorname: 'JOHN DOE', 63 | bankname: 'Access Bank', 64 | originatoramount: 'N/A' 65 | }, 66 | amount_settled: 1972, 67 | customer: { 68 | id: 1882300, 69 | name: 'Olaobaju Jesulayomi', 70 | phone_number: '+2349067985011', 71 | email: 'developers@flutterwavego.com', 72 | created_at: '2022-11-08T13:38:03.000Z' 73 | } 74 | } 75 | }) 76 | 77 | var payload = { 78 | id: '4186265', 79 | }; 80 | 81 | var resp = await trxInstance.verify(payload); 82 | expect(verifyTransactionStub).to.have.been.calledOnce; 83 | 84 | expect(resp).to.have.property('status', 'success'); 85 | expect(resp).to.have.property('data'); 86 | expect(resp).to.have.property('message', 'Transaction fetched successfully'); 87 | 88 | expect(resp.data).to.have.property('id', 4186265); 89 | expect(resp.data).to.have.property('status'); 90 | expect(resp.data).to.have.property('customer'); 91 | }); 92 | 93 | it('should successfully verify a payment by tx_ref', async function () { 94 | this.timeout(10000); 95 | 96 | const verifyTransactionbyTxStub = sinon 97 | .stub(trxInstance, 'verify_by_tx') 98 | .resolves({ 99 | status: 'success', 100 | message: 'Transaction fetched successfully', 101 | data: { 102 | id: 8415006, 103 | tx_ref: 'txref-DI0NzMx13', 104 | flw_ref: 'FLW-MOCK-3b10a512c4dae649e580a7e5747cfd2c', 105 | device_fingerprint: '2a4bf5d669b2a0cd4b684ffba8caaae8', 106 | amount: 2500, 107 | currency: 'NGN', 108 | charged_amount: 2500, 109 | app_fee: 35, 110 | merchant_fee: 0, 111 | processor_response: 'Please enter the OTP sent to your mobile number 080****** and email te**@rave**.com', 112 | auth_model: 'NOAUTH', 113 | ip: '54.75.161.64', 114 | narration: 'CARD Transaction ', 115 | status: 'successful', 116 | payment_type: 'card', 117 | created_at: '2025-02-27T18:29:34.000Z', 118 | account_id: 20937, 119 | card: { 120 | first_6digits: '418742', 121 | last_4digits: '4246', 122 | issuer: 'ACCESS BANK PLC DEBIT CLASSIC', 123 | country: 'NIGERIA NG', 124 | type: 'VISA', 125 | token: 'flw-t1nf-937086f0365b7334de60da246def40df-m03k', 126 | expiry: '09/32' 127 | }, 128 | meta: { 129 | __CheckoutInitAddress: 'https://cdpn.io/FlutterwaveEng/fullembedgrid/PoVpKqb?animations=run&forceRefresh=1740680880044&type=embed', 130 | source: 'docs-inline-test', 131 | consumer_mac: '92a3-912ba-1192a' 132 | }, 133 | amount_settled: 2462.37, 134 | customer: { 135 | id: 2362222, 136 | name: 'Ayomide Jimi-Oni', 137 | phone_number: '08100000000', 138 | email: 'test@mailinator.com', 139 | created_at: '2024-02-28T09:51:09.000Z' 140 | } 141 | } 142 | }) 143 | 144 | var payload = { 145 | tx_ref: 'txref-DI0NzMx13', 146 | }; 147 | 148 | var resp = await trxInstance.verify_by_tx(payload); 149 | expect(verifyTransactionbyTxStub).to.have.been.calledOnce; 150 | 151 | expect(resp).to.have.property('status', 'success'); 152 | expect(resp).to.have.property('data'); 153 | expect(resp).to.have.property('message', 'Transaction fetched successfully'); 154 | 155 | expect(resp.data).to.have.property('tx_ref', "txref-DI0NzMx13"); 156 | expect(resp.data).to.have.property('status'); 157 | expect(resp.data).to.have.property('customer'); 158 | }); 159 | 160 | it('should successfully return transaction events', async function () { 161 | this.timeout(10000); 162 | 163 | const getTransactionEventStub = sinon 164 | .stub(trxInstance, 'event') 165 | .resolves({ 166 | status: 'success', 167 | message: 'Transaction events fetched', 168 | data: [ 169 | { 170 | note: 'Launched Mobile Money as initial payment option', 171 | actor: 'customer@customer.com', 172 | object: 'modal', 173 | action: 'launched', 174 | context: 'mobile', 175 | created_at: '2023-06-23T12:24:12.004Z' 176 | }, 177 | { 178 | note: 'Initiated Checkout from https://ravemodal-dev.herokuapp.com/v3/hosted/pay', 179 | actor: 'customer@customer.com', 180 | object: 'modal', 181 | action: 'loaded', 182 | context: 'mobile', 183 | created_at: '2023-06-23T12:24:11.816Z' 184 | }, 185 | { 186 | note: 'Charge request successful - Pending verification', 187 | actor: 'customer@customer.com', 188 | object: 'modal', 189 | action: 'charge request', 190 | context: 'mobile', 191 | created_at: '2023-06-23T12:24:27.880Z' 192 | }, 193 | { 194 | note: 'Transaction Completed!', 195 | actor: 'customer@customer.com', 196 | object: 'TRANSACTION', 197 | action: 'completion', 198 | context: 'mobile', 199 | created_at: '2023-06-23T12:24:41.034Z' 200 | } 201 | ] 202 | }) 203 | 204 | var payload = { 205 | id: '4417681', 206 | }; 207 | 208 | var resp = await trxInstance.event(payload); 209 | expect(getTransactionEventStub).to.have.been.calledOnce; 210 | 211 | expect(resp).to.have.property('status', 'success'); 212 | expect(resp).to.have.property('data'); 213 | expect(resp).to.have.property('message', 'Transaction events fetched'); 214 | 215 | expect(resp.data[0]).to.have.property('note'); 216 | expect(resp.data[0]).to.have.property('actor'); 217 | }); 218 | 219 | it('should successfully return transaction fee', async function () { 220 | this.timeout(10000); 221 | 222 | const getTransactionFeeStub = sinon 223 | .stub(trxInstance, 'fee') 224 | .resolves({ 225 | status: 'success', 226 | message: 'Charged fee', 227 | data: { 228 | charge_amount: 1000, 229 | fee: 14, 230 | merchant_fee: 0, 231 | flutterwave_fee: 14, 232 | stamp_duty_fee: 0, 233 | currency: 'NGN' 234 | } 235 | }) 236 | 237 | var payload = { 238 | amount: 1000, 239 | currency: "NGN" 240 | }; 241 | 242 | var resp = await trxInstance.fee(payload); 243 | expect(getTransactionFeeStub).to.have.been.calledOnce; 244 | 245 | expect(resp).to.have.property('status', 'success'); 246 | expect(resp).to.have.property('data'); 247 | expect(resp).to.have.property('message', 'Charged fee'); 248 | 249 | expect(resp.data).to.have.property('charge_amount'); 250 | expect(resp.data).to.have.property('fee'); 251 | }); 252 | }); 253 | -------------------------------------------------------------------------------- /test/rave.misc.test.js: -------------------------------------------------------------------------------- 1 | var misc = require('../lib/rave.misc'); 2 | var base = require('../lib/rave.base'); 3 | 4 | var Promise = require('bluebird'); 5 | var mocha = require('mocha'); 6 | var chai = require('chai'); 7 | var expect = chai.expect; 8 | var chaiAsPromised = require('chai-as-promised'); 9 | 10 | var dotenv = require('dotenv').config(); 11 | 12 | const sinon = require('sinon'); 13 | const sinonChai = require('sinon-chai'); 14 | 15 | chai.use(chaiAsPromised); 16 | chai.use(sinonChai); 17 | 18 | describe('#Rave Misc', function () { 19 | const public_key = process.env.PUBLIC_KEY; 20 | const secret_key = process.env.SECRET_KEY; 21 | const ravebase = new base(public_key, secret_key); 22 | 23 | let miscInstance; 24 | let miscStub; 25 | 26 | beforeEach(() => { 27 | miscInstance = new misc(ravebase); 28 | }); 29 | 30 | afterEach(() => { 31 | sinon.restore(); 32 | }); 33 | 34 | it('should return NGN balance', async function () { 35 | this.timeout(10000); 36 | 37 | const fetchSingleBalanceSuccessStub = sinon 38 | .stub(miscInstance, 'bal_currency') 39 | .resolves({ 40 | body: { 41 | status: 'success', 42 | message: 'Wallet balance fetched', 43 | data: { 44 | currency: 'NGN', 45 | available_balance: 2168880, 46 | ledger_balance: 253125.82, 47 | }, 48 | }, 49 | }); 50 | 51 | var payload = { 52 | currency: 'NGN', 53 | }; 54 | 55 | var resp = await miscInstance.bal_currency(payload); 56 | 57 | expect(fetchSingleBalanceSuccessStub).to.have.been.calledOnce; 58 | expect(fetchSingleBalanceSuccessStub).to.have.been.calledOnceWith(payload); 59 | 60 | expect(resp.body).to.have.property('status', 'success'); 61 | expect(resp.body).to.have.property('data'); 62 | 63 | expect(resp.body.data).to.have.property('currency'); 64 | expect(resp.body.data).to.have.property('available_balance'); 65 | expect(resp.body.data).to.have.property('ledger_balance'); 66 | }); 67 | 68 | it('should return all wallet balances', async function () { 69 | this.timeout(10000); 70 | 71 | const fetchBalanceSuccessStub = sinon.stub(miscInstance, 'bal').resolves({ 72 | body: { 73 | status: 'success', 74 | message: 'Wallet balances fetched', 75 | data: [ 76 | { 77 | currency: 'NGN', 78 | available_balance: 2367840, 79 | ledger_balance: 253125.82, 80 | }, 81 | { 82 | currency: 'KES', 83 | available_balance: 0, 84 | ledger_balance: 1226.72, 85 | }, 86 | { 87 | currency: 'GHS', 88 | available_balance: 0, 89 | ledger_balance: 0, 90 | }, 91 | { 92 | currency: 'USD', 93 | available_balance: 0, 94 | ledger_balance: 472.08, 95 | }, 96 | { 97 | currency: 'EUR', 98 | available_balance: 0, 99 | ledger_balance: 0, 100 | }, 101 | { 102 | currency: 'ZAR', 103 | available_balance: 0, 104 | ledger_balance: 0, 105 | }, 106 | { 107 | currency: 'GBP', 108 | available_balance: 0, 109 | ledger_balance: 0, 110 | }, 111 | { 112 | currency: 'TZS', 113 | available_balance: 0, 114 | ledger_balance: 0, 115 | }, 116 | { 117 | currency: 'UGX', 118 | available_balance: 0, 119 | ledger_balance: 0, 120 | }, 121 | { 122 | currency: 'RWF', 123 | available_balance: 0, 124 | ledger_balance: 5000, 125 | }, 126 | { 127 | currency: 'ZMW', 128 | available_balance: 0, 129 | ledger_balance: 0, 130 | }, 131 | { 132 | currency: 'INR', 133 | available_balance: 0, 134 | ledger_balance: 0, 135 | }, 136 | { 137 | currency: 'XOF', 138 | available_balance: 0, 139 | ledger_balance: 0, 140 | }, 141 | { 142 | currency: 'MUR', 143 | available_balance: 0, 144 | ledger_balance: 0, 145 | }, 146 | { 147 | currency: 'ETB', 148 | available_balance: 0, 149 | ledger_balance: 0, 150 | }, 151 | ], 152 | }, 153 | }); 154 | 155 | var resp = await miscInstance.bal(); 156 | 157 | expect(fetchBalanceSuccessStub).to.have.been.calledOnce; 158 | 159 | expect(resp.body).to.have.property('status', 'success'); 160 | expect(resp.body).to.have.property('data'); 161 | 162 | expect(resp.body.data[0]).to.have.property('currency'); 163 | expect(resp.body.data[0]).to.have.property('available_balance'); 164 | expect(resp.body.data[0]).to.have.property('ledger_balance'); 165 | }); 166 | 167 | it('should initiate BVN consent and return success message', async function () { 168 | this.timeout(10000); 169 | 170 | const resolveInitBVNSuccessStub = sinon.stub(miscInstance, 'bvn').resolves({ 171 | body: { 172 | status: 'success', 173 | message: 'Bvn verification initiated', 174 | data: { 175 | url: 'https://nibss-bvn-consent-management.dev-flutterwave.com/cms/BvnConsent?session=MWNkNDI4ZWYtMjgwNy00ZjA1LWE5NzUtNzUyZGUyZDRjZWQz', 176 | reference: 'FLW71DC60942BAD76D2BD5B4E' 177 | } 178 | }, 179 | }); 180 | 181 | var payload = { 182 | bvn: "12347832211", 183 | firstname: "Lyra", 184 | lastname: "Balacqua", 185 | redirect_url: "https://example-url.company.com" 186 | }; 187 | 188 | var resp = await miscInstance.bvn(payload); 189 | 190 | expect(resolveInitBVNSuccessStub).to.have.been.calledOnce; 191 | expect(resolveInitBVNSuccessStub).to.have.been.calledOnceWith(payload); 192 | 193 | expect(resp.body).to.have.property('status', 'success'); 194 | expect(resp.body).to.have.property('message', 'Bvn verification initiated'); 195 | expect(resp.body).to.have.property('data'); 196 | 197 | expect(resp.body.data).to.have.property('reference'); 198 | expect(resp.body.data).to.have.property('url'); 199 | }); 200 | 201 | it('should verify BVN consent and return success message', async function () { 202 | this.timeout(10000); 203 | 204 | const resolveVerifyBVNSuccessStub = sinon.stub(miscInstance, 'verifybvn').resolves({ 205 | body: { 206 | status: 'success', 207 | message: 'Bvn details fetched', 208 | data: { 209 | first_name: 'Lyra', 210 | last_name: 'Balacqua', 211 | status: 'INITIATED', 212 | reference: 'FLW71DC60942BAD76D2BD5B4E', 213 | callback_url: null, 214 | bvn_data: null, 215 | created_at: '2024-02-16T08:28:10.000Z' 216 | } 217 | }, 218 | }); 219 | 220 | var payload = { 221 | reference: "FLW71DC60942BAD76D2BD5B4E" 222 | }; 223 | 224 | var resp = await miscInstance.verifybvn(payload); 225 | 226 | expect(resolveVerifyBVNSuccessStub).to.have.been.calledOnce; 227 | expect(resolveVerifyBVNSuccessStub).to.have.been.calledOnceWith(payload); 228 | 229 | expect(resp.body).to.have.property('status', 'success'); 230 | expect(resp.body).to.have.property('message', 'Bvn details fetched'); 231 | expect(resp.body).to.have.property('data'); 232 | }); 233 | 234 | it('should verify resolve bank account details', async function () { 235 | this.timeout(10000); 236 | 237 | const resolveAccountSuccessStub = sinon 238 | .stub(miscInstance, 'verify_Account') 239 | .resolves({ 240 | body: { 241 | status: 'success', 242 | message: 'Account details fetched', 243 | data: { 244 | account_number: '0690000032', 245 | account_name: 'Pastor Bright', 246 | }, 247 | }, 248 | }); 249 | 250 | var payload = { 251 | account_number: '0690000032', 252 | account_bank: '044', 253 | }; 254 | 255 | var resp = await miscInstance.verify_Account(payload); 256 | // console.log(resp); 257 | 258 | expect(resolveAccountSuccessStub).to.have.been.calledOnce; 259 | expect(resolveAccountSuccessStub).to.have.been.calledOnceWith(payload); 260 | 261 | expect(resp.body).to.have.property('status', 'success'); 262 | expect(resp.body).to.have.property('data'); 263 | 264 | expect(resp.body.data).to.have.property('account_number'); 265 | expect(resp.body.data).to.have.property('account_name'); 266 | }); 267 | 268 | it('should fetch a balance by currency', async function () { 269 | this.timeout(10000); 270 | 271 | const fetchBalanceByCurrencySuccessStub = sinon 272 | .stub(miscInstance, 'bal_currency') 273 | .resolves({ 274 | body: { 275 | status: 'success', 276 | message: 'Wallet balance fetched', 277 | data: { 278 | currency: 'NGN', 279 | available_balance: 4988877.82, 280 | ledger_balance: 21072145.6 281 | } 282 | }, 283 | }); 284 | 285 | var payload = { 286 | currency: 'NGN', 287 | }; 288 | 289 | var resp = await miscInstance.bal_currency(payload); 290 | // console.log(resp); 291 | 292 | expect(fetchBalanceByCurrencySuccessStub).to.have.been.calledOnce; 293 | expect(fetchBalanceByCurrencySuccessStub).to.have.been.calledOnceWith(payload); 294 | 295 | expect(resp.body).to.have.property('status', 'success'); 296 | expect(resp.body).to.have.property('data'); 297 | 298 | expect(resp.body.data).to.have.property('currency'); 299 | expect(resp.body.data).to.have.property('available_balance'); 300 | expect(resp.body.data).to.have.property('ledger_balance'); 301 | }); 302 | }); 303 | -------------------------------------------------------------------------------- /documentation/payment-plan.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # PAYMENT PLANS 6 | 7 | We recommend reading the main readme first, to understand the requirements for using the library and how to initiate this in your apps. This guide assumes you've read that. 8 | 9 | Manage Payment Plans via any of these methods: 10 | 1. [Create Payment Plan](#create-payment-plan) 11 | 2. [Get a Payment Plan](#get-a-payment-plan) 12 | 3. [Get Payment Plans](#get-payment-plans) 13 | 4. [Update Payment Plan](#update-a-payment-plan) 14 | 5. [Cancel Payment Plan](#cancel-a-payment-plan) 15 | 16 | 17 | ## Create payment plan 18 | 19 | This describes how to create a payment plan 20 | 21 | ```javascript 22 | const Flutterwave = require('flutterwave-node-v3'); 23 | 24 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 25 | 26 | const createPaymentPlan = async () => { 27 | try { 28 | const payload = { 29 | amount: 1000, 30 | name: 'SDK test Plan', //This is the name of the payment, it will appear on the subscription reminder emails 31 | interval: 'monthly', //This will determine the frequency of the charges for this plan. Could be monthly, weekly, etc. 32 | }; 33 | 34 | const response = await flw.PaymentPlan.create(payload); 35 | console.log(response); 36 | } catch (error) { 37 | console.log(error); 38 | } 39 | }; 40 | 41 | createPaymentPlan(); 42 | ``` 43 | 44 | Sample Response 45 | 46 | ```javascript 47 | { 48 | "status": "success", 49 | "message": "Payment plan created", 50 | "data": { 51 | "id": 52045, 52 | "name": "SDK test Plan", 53 | "amount": "100", 54 | "interval": "monthly", 55 | "duration": 0, 56 | "status": "active", 57 | "currency": "NGN", 58 | "plan_token": "rpp_cd93e2fa88e065b960bf", 59 | "created_at": "2023-07-04T09:16:42.000Z" 60 | } 61 | } 62 | ``` 63 | 64 | ## Get payment plans 65 | 66 | This describes how to fetch all payment plans on your account 67 | 68 | ```javascript 69 | const Flutterwave = require('flutterwave-node-v3'); 70 | 71 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 72 | 73 | const fetchAllPlans = async () => { 74 | try { 75 | const response = await flw.PaymentPlan.get_all(); 76 | console.log(response); 77 | } catch (error) { 78 | console.log(error); 79 | } 80 | }; 81 | 82 | fetchAllPlans(); 83 | ``` 84 | 85 | Sample Response 86 | 87 | ```javascript 88 | { 89 | "status": "success", 90 | "message": "Payment plans fetched", 91 | "meta": { 92 | "page_info": { 93 | "total": 106, 94 | "current_page": 1, 95 | "total_pages": 11 96 | } 97 | }, 98 | "data": [ 99 | { 100 | "id": 37829, 101 | "name": "testing", 102 | "amount": 100, 103 | "interval": "weekly", 104 | "duration": 4, 105 | "status": "cancelled", 106 | "currency": "NGN", 107 | "plan_token": "rpp_0aac3d0aa3f0c18565c0", 108 | "created_at": "2023-06-14T11:57:26.000Z" 109 | }, 110 | { 111 | "id": 37828, 112 | "name": "API monitor", 113 | "amount": 100, 114 | "interval": "monthly", 115 | "duration": 0, 116 | "status": "cancelled", 117 | "currency": "NGN", 118 | "plan_token": "rpp_27ea9a4ef60dae5e7fc8", 119 | "created_at": "2023-06-14T11:48:26.000Z" 120 | }, 121 | { 122 | "id": 36074, 123 | "name": "the akhlm postman plan 2", 124 | "amount": 100, 125 | "interval": "monthly", 126 | "duration": 5, 127 | "status": "cancelled", 128 | "currency": "NGN", 129 | "plan_token": "rpp_134b476d4d1f9181a219", 130 | "created_at": "2023-05-22T14:15:05.000Z" 131 | }, 132 | { 133 | "id": 34444, 134 | "name": "postman plan 0", 135 | "amount": 100, 136 | "interval": "monthly", 137 | "duration": 8, 138 | "status": "cancelled", 139 | "currency": "NGN", 140 | "plan_token": "rpp_89b6c76c0394af004913", 141 | "created_at": "2023-03-26T21:05:26.000Z" 142 | }, 143 | { 144 | "id": 34185, 145 | "name": "A sample KES monthly plan", 146 | "amount": 0, 147 | "interval": "monthly", 148 | "duration": 12, 149 | "status": "active", 150 | "currency": "NGN", 151 | "plan_token": "rpp_2f711270c4de5c2393d3", 152 | "created_at": "2023-03-15T00:34:50.000Z" 153 | }, 154 | { 155 | "id": 33857, 156 | "name": "PHPSDK Test Plan", 157 | "amount": 1600, 158 | "interval": "monthly", 159 | "duration": 1, 160 | "status": "cancelled", 161 | "currency": "NGN", 162 | "plan_token": "rpp_0d087b5a4644f78252ad", 163 | "created_at": "2023-03-03T14:29:37.000Z" 164 | }, 165 | { 166 | "id": 33856, 167 | "name": "PHPSDK Test Plan", 168 | "amount": 1600, 169 | "interval": "monthly", 170 | "duration": 1, 171 | "status": "cancelled", 172 | "currency": "NGN", 173 | "plan_token": "rpp_570f8a07e6c190a91f4f", 174 | "created_at": "2023-03-03T14:29:36.000Z" 175 | }, 176 | { 177 | "id": 33855, 178 | "name": "PHPSDK Test Plan", 179 | "amount": 1600, 180 | "interval": "monthly", 181 | "duration": 1, 182 | "status": "cancelled", 183 | "currency": "NGN", 184 | "plan_token": "rpp_4f2926d1f3d1a56915a1", 185 | "created_at": "2023-03-03T14:29:33.000Z" 186 | }, 187 | { 188 | "id": 33850, 189 | "name": "PHPSDK Test Plan", 190 | "amount": 1600, 191 | "interval": "monthly", 192 | "duration": 1, 193 | "status": "cancelled", 194 | "currency": "NGN", 195 | "plan_token": "rpp_98a4ebf8b3dfc7f494a1", 196 | "created_at": "2023-03-03T14:13:47.000Z" 197 | }, 198 | { 199 | "id": 33849, 200 | "name": "PHPSDK Test Plan", 201 | "amount": 1600, 202 | "interval": "monthly", 203 | "duration": 1, 204 | "status": "cancelled", 205 | "currency": "NGN", 206 | "plan_token": "rpp_b6cc20cb87ee9a64d879", 207 | "created_at": "2023-03-03T14:13:39.000Z" 208 | } 209 | ] 210 | } 211 | ``` 212 | 213 | 214 | ## Get a payment plan 215 | 216 | This describes how to get a single payment plan 217 | 218 | ```javascript 219 | const Flutterwave = require('flutterwave-node-v3'); 220 | 221 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 222 | 223 | const fetchPlan = async () => { 224 | try { 225 | const payload = { 226 | id: '52045', //This is the unique ìdof the payment plan you want to fetch. It is returned in the call to create a payment plan asdata.id` 227 | }; 228 | 229 | const response = await flw.PaymentPlan.get_plan(payload); 230 | console.log(response); 231 | } catch (error) { 232 | console.log(error); 233 | } 234 | }; 235 | 236 | fetchPlan(); 237 | ``` 238 | 239 | Sample Response 240 | 241 | ```javascript 242 | { 243 | "status": "success", 244 | "message": "Payment plan fetched", 245 | "data": { 246 | "id": 52045, 247 | "name": "SDK test Plan", 248 | "amount": 100, 249 | "interval": "monthly", 250 | "duration": 0, 251 | "status": "active", 252 | "currency": "NGN", 253 | "plan_token": "rpp_cd93e2fa88e065b960bf", 254 | "created_at": "2023-07-04T09:16:42.000Z" 255 | } 256 | } 257 | ``` 258 | 259 | ## Update a payment plan 260 | 261 | This describes how to update an existing payment plan 262 | 263 | ```javascript 264 | const Flutterwave = require('flutterwave-node-v3'); 265 | 266 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 267 | 268 | const updatePlan = async () => { 269 | try { 270 | const payload = { 271 | id: '34185', //This is the unique ìdof the payment plan you want to fetch. It is returned in the call to create a payment plan asdata.id` 272 | name: 'A sample KES monthly plan', 273 | status: 'active', 274 | }; 275 | 276 | const response = await flw.PaymentPlan.update(payload); 277 | console.log(response); 278 | } catch (error) { 279 | console.log(error); 280 | } 281 | }; 282 | 283 | updatePlan(); 284 | ``` 285 | 286 | Sample Response 287 | 288 | ```javascript 289 | { 290 | "status": "success", 291 | "message": "Payment plan updated", 292 | "data": { 293 | "id": 34185, 294 | "name": "A sample KES monthly plan", 295 | "plan_token": "rpp_2f711270c4de5c2393d3", 296 | "status": "active", 297 | "currency": "NGN", 298 | "amount": 0, 299 | "duration": 12, 300 | "interval": "monthly", 301 | "created_at": "2023-03-15T00:34:50.000Z" 302 | } 303 | } 304 | ``` 305 | 306 | ## Cancel a payment plan 307 | This describes how to cancel an existing payment plan 308 | 309 | ```javascript 310 | const Flutterwave = require('flutterwave-node-v3'); 311 | 312 | const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY ); 313 | 314 | const cancelPlan = async () => { 315 | try { 316 | const payload = { 317 | id: '34185', //This is the unique ìd` of the payment plan you want to cancel 318 | }; 319 | 320 | const response = await flw.PaymentPlan.cancel(payload); 321 | console.log(response); 322 | } catch (error) { 323 | console.log(error); 324 | } 325 | }; 326 | 327 | cancelPlan(); 328 | ``` 329 | 330 | Sample Response 331 | 332 | ```javascript 333 | { 334 | "status": "success", 335 | "message": "Payment plan cancelled", 336 | "data": { 337 | "id": 34185, 338 | "name": "A sample KES monthly plan", 339 | "plan_token": "rpp_2f711270c4de5c2393d3", 340 | "status": "cancelled", 341 | "currency": "NGN", 342 | "amount": 0, 343 | "duration": 12, 344 | "interval": "monthly", 345 | "created_at": "2023-03-15T00:34:50.000Z" 346 | } 347 | } 348 | ``` --------------------------------------------------------------------------------