├── .DS_Store ├── .env.example ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.yml ├── pull_request_template.md └── workflows │ ├── change-review.yml │ ├── ruby-publish.yml │ └── security-scan.yml ├── .gitignore ├── .rspec ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── changelog.md ├── flutterwave_sdk.gemspec ├── lib ├── flutterwave_sdk.rb └── flutterwave_sdk │ ├── error.rb │ ├── flutterwave_modules │ ├── base_endpoints.rb │ └── util.rb │ ├── flutterwave_objects │ ├── account_payment.rb │ ├── bank.rb │ ├── bank_transfer.rb │ ├── base │ │ ├── base.rb │ │ └── card_base.rb │ ├── beneficiaries.rb │ ├── bills.rb │ ├── card.rb │ ├── misc.rb │ ├── mobile_money.rb │ ├── otp.rb │ ├── payment_plan.rb │ ├── preauthorise.rb │ ├── qr.rb │ ├── settlements.rb │ ├── subaccount.rb │ ├── subscriptions.rb │ ├── tokenized_charge.rb │ ├── transactions.rb │ ├── transfer.rb │ ├── ussd_payment.rb │ ├── virtual_account_number.rb │ └── virtual_card.rb │ └── version.rb └── spec ├── flutterwave_card_spec.rb ├── flutterwave_momo_spec.rb ├── flutterwave_momo_tzs_spec.rb ├── flutterwave_sdk_spec.rb └── spec_helper.rb /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flutterwave/Ruby-v3/e977378986fefc5552d6104275787ff16a18ac48/.DS_Store -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | TEST_SECRET_KEY= 2 | TEST_PUBLIC_KEY= 3 | TEST_ENCRYPTION_KEY= 4 | -------------------------------------------------------------------------------- /.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/Ruby/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/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 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### Description 4 | 5 | 6 | #### Related Issue 7 | 8 | 9 | 10 | 11 | 12 | #### Motivation and Context 13 | 14 | 15 | #### How Has This Been Tested? 16 | 17 | 18 | 19 | 20 | #### Types of changes 21 | 22 | - [ ] Bug fix (non-breaking change which fixes an issue) 23 | - [ ] Refactor (non-breaking change which improves implementation) 24 | - [ ] Performance (non-breaking change which improves performance. Please add associated performance test and results) 25 | - [ ] New feature (non-breaking change which adds functionality) 26 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 27 | - [ ] Non-functional change (xml comments/documentation/etc) 28 | 29 | #### Checklist: 30 | 31 | 32 | - [ ] My code follows the code style of this project. 33 | - [ ] I have read the **CONTRIBUTING** [document](https://github.com/QuantConnect/Lean/blob/master/CONTRIBUTING.md). 34 | - [ ] I have added tests to cover my changes. 35 | - [ ] All new and existing tests passed. 36 | - [ ] My branch follows the naming convention `bug--` or `feature--` 37 | 38 | 39 | @Flutterwave/Corvus97 What do you think about these updates? 40 | -------------------------------------------------------------------------------- /.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 | strategy: 14 | matrix: 15 | ruby-version: ["3.1", "3.0", "2.7"] 16 | 17 | steps: 18 | - name: checkout code 19 | uses: actions/checkout@v2 20 | 21 | - name: setup ruby environment 22 | uses: ruby/setup-ruby@v1 23 | with: 24 | bundler-cache: true 25 | ruby-version: ${{ matrix.ruby-version }} 26 | 27 | - name: install ruby dependencies 28 | run: | 29 | gem install bundler 30 | bundle install --jobs 4 --retry 3 31 | 32 | - name: run unit tests and coverage scan 33 | env: 34 | PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} 35 | ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} 36 | RAVE_SECRET_KEY: ${{ secrets.SECRET_KEY }} 37 | run: | 38 | bundle exec rspec --format progress --format json --out coverage/coverage.json 39 | 40 | - name: upload coverage report to codecov 41 | uses: codecov/codecov-action@v2 42 | with: 43 | file: coverage/coverage.json 44 | 45 | - name: push build status to slack 46 | uses: 8398a7/action-slack@v3 47 | with: 48 | status: ${{ job.status }} 49 | fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest 50 | env: 51 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 52 | if: always() 53 | -------------------------------------------------------------------------------- /.github/workflows/ruby-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish changes to Rubygems 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | check-readme-and-changelog: 9 | runs-on: ubuntu-latest 10 | env: 11 | OS: ubuntu-latest 12 | ruby-version: "3.1" 13 | steps: 14 | - name: checkout code 15 | uses: actions/checkout@v2 16 | 17 | - name: check for changes in readme and changelog files 18 | run: | 19 | if ! git diff --quiet HEAD~ HEAD -- README.md CHANGELOG.md; then 20 | echo "README and/or CHANGELOG have been modified. Proceeding with deployment." 21 | else 22 | echo "README and/or CHANGELOG have not been modified. Terminating deployment." 23 | exit 1 24 | fi 25 | 26 | - name: push build status to Slack 27 | uses: 8398a7/action-slack@v3 28 | with: 29 | status: ${{ job.status }} 30 | fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest 31 | env: 32 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 33 | if: always() 34 | 35 | publish: 36 | needs: check-readme-and-changelog 37 | runs-on: ubuntu-latest 38 | env: 39 | OS: ubuntu-latest 40 | ruby-version: "3.1" 41 | steps: 42 | - name: checkout code 43 | uses: actions/checkout@v2 44 | 45 | - name: Setup ruby environment 46 | uses: actions/setup-ruby@v1 47 | with: 48 | ruby-version: "3.1" 49 | 50 | - name: install ruby dependencies 51 | run: bundle install 52 | 53 | - name: Publish gems to Rubygems 54 | env: 55 | GEM_HOST_API_KEY: ${{secrets.GEM_HOST_API_KEY}} 56 | run: gem push gems/*.gem 57 | 58 | - name: push build status to Slack 59 | uses: 8398a7/action-slack@v3 60 | with: 61 | status: ${{ job.status }} 62 | fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest 63 | env: 64 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 65 | if: always() 66 | -------------------------------------------------------------------------------- /.github/workflows/security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Security scan on all changes (Commits/PRs) 2 | 3 | on: 4 | push: 5 | branches: ['main', 'master', 'pilot', '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 | PYTHON: '3.7' 16 | steps: 17 | - name: checkout code 18 | uses: actions/checkout@v2 19 | 20 | 21 | - name: Checkmarx One ClI Action 22 | uses: checkmarx/ast-github-action@main 23 | with: 24 | project_name: Ruby-v3 25 | cx_tenant: Flutterwave 26 | base_uri: https://eu.ast.checkmarx.net/ 27 | cx_client_id: ${{ secrets.CX_CLIENT_ID }} 28 | cx_client_secret: ${{ secrets.CX_CLIENT_SECRET }} 29 | additional_params: --scan-types sast,iac-security,api-security,sca,container-security 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | 10 | .env 11 | /sample_code 12 | sample_code/ 13 | sample_code 14 | 15 | # rspec failure tracking 16 | .rspec_status 17 | charge_test.rb 18 | mobile_money_test.rb 19 | account_payment_test.rb 20 | bank_transfer_test.rb 21 | ussd_test.rb 22 | qr_test.rb 23 | tokenized_test.rb 24 | transactions_test.rb 25 | transfers_test.rb 26 | bank_test.rb 27 | misc_test.rb 28 | payment_plan_test.rb 29 | beneficiaries_test.rb 30 | subscriptions_test.rb 31 | virtual_card_test.rb 32 | subaccount_test.rb 33 | settlements_test.rb 34 | otp_test.rb 35 | virtual_account_number_test.rb 36 | bills_test.rb 37 | preauth_test.rb 38 | rspec_results.html 39 | flutterwave_sdk-0.1.0.gem 40 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: ruby 3 | cache: bundler 4 | rvm: 5 | - 2.6.3 6 | before_install: gem install bundler -v 2.1.4 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at developers@flutterwavego.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [https://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: https://contributor-covenant.org 74 | [version]: https://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /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](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 🦋 96 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in flutterwave_sdk.gemspec 4 | gemspec 5 | 6 | gem "rake", "~> 12.0" 7 | gem "rspec", "~> 3.0" 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | flutterwave_sdk (0.1.1) 5 | httparty (~> 0.16.3) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | diff-lcs (1.3) 11 | dotenv (2.8.1) 12 | httparty (0.16.4) 13 | mime-types (~> 3.0) 14 | multi_xml (>= 0.5.2) 15 | mime-types (3.4.1) 16 | mime-types-data (~> 3.2015) 17 | mime-types-data (3.2023.0218.1) 18 | multi_xml (0.6.0) 19 | rake (12.3.3) 20 | rspec (3.9.0) 21 | rspec-core (~> 3.9.0) 22 | rspec-expectations (~> 3.9.0) 23 | rspec-mocks (~> 3.9.0) 24 | rspec-core (3.9.1) 25 | rspec-support (~> 3.9.1) 26 | rspec-expectations (3.9.0) 27 | diff-lcs (>= 1.2.0, < 2.0) 28 | rspec-support (~> 3.9.0) 29 | rspec-mocks (3.9.1) 30 | diff-lcs (>= 1.2.0, < 2.0) 31 | rspec-support (~> 3.9.0) 32 | rspec-support (3.9.2) 33 | 34 | PLATFORMS 35 | ruby 36 | 37 | DEPENDENCIES 38 | bundler (~> 2.1.4) 39 | dotenv (~> 2.8.1) 40 | flutterwave_sdk! 41 | rake (~> 12.0) 42 | rspec (~> 3.0) 43 | 44 | BUNDLED WITH 45 | 2.1.4 46 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Ifunanya Ikemma 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Flutterwave v3 Ruby Library 6 | 7 | This is a Ruby gem for easy integration of Flutterwave V3 API for various applications written in Ruby language from [Flutterwave](https://rave.flutterwave.com/). See [Here](https://developer.flutterwave.com/reference) for Flutterwave V3 API Docs. 8 | 9 | ## Installation 10 | 11 | Add this line to your application's Gemfile: 12 | 13 | ```ruby 14 | gem 'flutterwave_sdk' 15 | ``` 16 | 17 | And then execute: 18 | 19 | $ bundle install 20 | 21 | Or install it yourself as: 22 | 23 | $ gem install flutterwave_sdk 24 | 25 | ## Usage 26 | 27 | ## Instantiate Flutterwave Object 28 | To use [Flutterwave Ruby SDK](https://ravesandbox.flutterwave.com), you need to instantiate the RaveRuby class with your [API](https://dashboard.flutterwave.com/dashboard/settings/apis) keys which are your public, secret and encryption keys. We recommend that you store your API keys in your environment variable named `FLUTTERWAVE_PUBLIC_KEY`, `FLUTTERWAVE_SECRET_KEY` and `FLUTTERWAVE_ENCRYPTION_KEY`. Instantiating your flutterwave object after adding your API keys in your environment is as illustrated below: 29 | 30 | ```ruby 31 | payment = Flutterwave.new 32 | ``` 33 | This throws a `FLUTTERWAVEBadKeyError` if no key is found in the environment variable or invalid public or secret key is found. 34 | 35 | #### Instantiate FLutterwave object in sandbox without environment variable: 36 | 37 | You can instantiate your Flutterwave object by setting your public, secret and encryption keys by passing them as an argument of the `Flutterwave` class just as displayed below: 38 | 39 | ```ruby 40 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxxx-X", "FLWSECK-xxxxxxxxx-X", "xxxxxxxxxxx") 41 | ``` 42 | 43 | #### `NOTE:` It is best practice to always set your API keys to your environment variable for security purpose. Please be warned not use this package without setting your API keys in your environment variables in production. 44 | 45 | #### To instantiate Flutterwave object in production with environment variable: 46 | 47 | Simply use it as displayed below: 48 | 49 | ```ruby 50 | Payment = Flutterwave.new("YOUR_FLUTTERWAVE_LIVE_PUBLIC_KEY", "YOUR_FLUTTERWAVE_LIVE_SECRET_KEY", "YOUR_ENCRYPTION_KEY", true) 51 | ``` 52 | 53 | ### Flutterwave Objects 54 | - [Card.new(payment)](#cardnewpayment) 55 | - [AccountPayment.new(payment)](#accountpaymentnewpayment) 56 | - [Bank.new(payment)](#banknewpayment) 57 | - [Bills.new(payment)](#billsnewpayment) 58 | - [BankTransfer.new(payment)](banktransfernewpayment) 59 | - [Beneficiaries.new(payment)](#beneficiariesnewpayment) 60 | - [USSD.new(payment)](#ussdnewpayment) 61 | - [Transfer.new(payment)](#transfernewpayment) 62 | - [VirtualCard.new(payment)](#virtualcardnewpayment) 63 | - [TokenizedCharge.new(payment)](#tokenizedchargenewpayment) 64 | - [Settlements.new(payment)](#settlementsnewpayment) 65 | - [QR.new(payment)](#qrnewpayment) 66 | - [Transactions.new(payment)](#transactionsnewpayment) 67 | - [VirtualAccountNumber.new(payment)](#virtualaccountnumbernewpayment) 68 | - [Subscriptions.new(payment)](#subscriptionsnewpayment) 69 | - [OTP.new(payment)](#otpnewpayment) 70 | - [Subaccount.new(payment)](#subaccountnewpayment) 71 | - [PaymentPlan.new(payment)](#paymentplannewpayment) 72 | - [MobileMoney.new(payment)](#mobilemoneynewpayment) 73 | - [Misc.new(payment)](#miscnewpayment) 74 | - [Preauth.new(payment)](preauthnewpayment) 75 | 76 | ## Card.new(payment) 77 | 78 | > NB - Flutterwave's direct card charge endpoint requires PCI-DSS compliance 79 | 80 | > To charge cards, you will need to be PCI DSS compliant. If you are, you can proceed to charge cards. 81 | Alternatively, you can use any of our other payment methods such as Standard, Inline or SDKs which do not require processing card details directly and do not also require payload encryption. 82 | 83 | 84 | To perform account transactions, instantiate the card object and pass Flutterwave object as its argument. 85 | #### Its functions includes: 86 | 87 | - .initiate_charge 88 | - .validate_charge 89 | - .verify_charge 90 | 91 | 92 | ## Full Account Transaction Flow 93 | 94 | ```ruby 95 | require './flutterwave_sdk' 96 | 97 | # This is a Flutterwave object which is expecting public, secret and encrption keys 98 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxx-X", "FLWSECK-xxxxxxxxx-X", "xxxxxxxxxxxxxxxxxxxxxxx") 99 | 100 | # This is used to perform card charge 101 | 102 | payload = { 103 | 104 | "card_number" => "5531886652142950", 105 | "cvv" => "564", 106 | "expiry_month" => "09", 107 | "expiry_year" => "22", 108 | "currency" => "NGN", 109 | "amount" => "10", 110 | "email" => "xxxxxxxxxx@gmail.com", 111 | "fullname" => "Test Name", 112 | "tx_ref" => "MC-3243e-if-12", 113 | "redirect_url" => "https://webhook.site/399" 114 | 115 | } 116 | charge_card = Card.new(payment) 117 | 118 | response = charge_card.initiate_charge(payload) 119 | puts response 120 | 121 | # update payload with suggested auth 122 | if response["meta"]["authorization"]["mode"] 123 | suggested_auth = response["meta"]["authorization"]["mode"] 124 | auth_arg = charge_card.get_auth_type(suggested_auth) 125 | if auth_arg == :pin 126 | updated_payload = charge_card.update_payload(suggested_auth, payload, pin: { "pin" => "3310"} ) 127 | elsif auth_arg == :address 128 | updated_payload = charge_card.update_payload(suggested_auth, payload, address:{ "zipcode"=> "07205", "city"=> "Hillside", "address"=> "470 Mundet PI", "state"=> "NJ", "country"=> "US"}) 129 | end 130 | 131 | # perform the second charge after payload is updated with suggested auth 132 | response = charge_card.initiate_charge(updated_payload) 133 | print response 134 | 135 | # perform validation if it is required 136 | if response["data"]["status"] == "pending" || "success-pending-validation" 137 | response = charge_card.validate_charge(response["data"]["flw_ref"], "12345") 138 | print response 139 | end 140 | else 141 | # You can handle the get the auth url from this response and load it for the customer to complete the transaction if an auth url is returned in the response. 142 | print response 143 | end 144 | 145 | # verify charge 146 | response = charge_card.verify_charge(response["data"]["id"]) 147 | print response 148 | 149 | ``` 150 | 151 | ## AccountPayment.new(payment) 152 | #### Its functions includes: 153 | 154 | - .initiate_charge 155 | - .validate_charge 156 | - .verify_charge 157 | 158 | ## Full Account Transaction Flow 159 | 160 | ```ruby 161 | require './flutterwave_sdk' 162 | 163 | # This is a Flutterwave object which is expecting public, secret and encrption keys 164 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxx-X", "FLWSECK-xxxxxxx-X", "xxxxxxx") 165 | 166 | payload = { 167 | "tx_ref" => "MC-1585230ew9v505010", 168 | "amount" => "100", 169 | "account_bank" => "044", 170 | "account_number" => "0690000037", 171 | "currency" => "NGN", 172 | "email" => "xxxxxxx@gmail.com", 173 | "phone_number" => "09000000000", 174 | "fullname" => "Test Name" 175 | } 176 | 177 | account_payment_ng = AccountPayment.new(payment) 178 | 179 | response = account_payment_ng.initiate_charge(payload) 180 | print response 181 | 182 | #validate payment with OTP 183 | if response["data"]["meta"]["authorization"]["mode"] == "otp" 184 | response = account_payment_ng.validate_charge(response["data"]["flw_ref"], "12345") 185 | print response 186 | else 187 | print response 188 | 189 | end 190 | 191 | #verify transaction 192 | response = account_payment_ng.verify_charge(response["data"]["tx_ref"]) 193 | 194 | print response 195 | 196 | ``` 197 | 198 | 199 | ## Bank.new(payment) 200 | #### Its functions includes: 201 | 202 | - .get_all_banks 203 | - .get_bank_branch 204 | 205 | ## See the full flow below 206 | 207 | ```ruby 208 | 209 | require './flutterwave_sdk' 210 | 211 | # This is a Flutterwave object which is expecting public, secret and encrption keys 212 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxx-X", "FLWSECK-xxxxxxxxxx-X", "xxxxxxxxx") 213 | bank = Bank.new(payment) 214 | 215 | #get all banks 216 | response = bank.get_all_banks("NG") 217 | print response 218 | 219 | # get bank branches 220 | response = bank.get_bank_branch(280) 221 | print response 222 | 223 | ``` 224 | 225 | ## Bills.new(payment) 226 | #### Its functions includes: 227 | 228 | - .create_bill_payment 229 | - .create_bulk_bill_payments 230 | - .get_status_of_a_bill_payment 231 | - .update_bills_order 232 | - .validate_bill_service 233 | - .get_bill_categories 234 | - .get_bill_payment_agencies 235 | - .get_amount_for_a_product 236 | - .get_bill_payments 237 | - .get_products_under_an_agency 238 | - .create_order_using_billing_code_and_productid 239 | 240 | ## See full flow below 241 | 242 | ```ruby 243 | require './flutterwave_sdk' 244 | 245 | # This is a Flutterwave object which is expecting public, secret and encrption keys 246 | payment = Flutterwave.new("FLWPUBK_TEST-3xxxxxxxxxx-X", "FLWSECK_TEST-xxxxxxxxx-X", "xxxxxxxxxxxxx") 247 | bill = Bills.new(payment) 248 | 249 | 250 | # Create a bill payment 251 | payload = { 252 | "country" => "NG", 253 | "customer" => "+23490803840303", 254 | "amount" => 500, 255 | "recurrence" => "ONCE", 256 | "type" => "AIRTIME", 257 | "reference" => "ifunaya-0987654" 258 | } 259 | 260 | response = bill.create_bill_payment(payload) 261 | print response 262 | 263 | #bulk bill payments 264 | payload = { 265 | "bulk_reference" => "edf-12de5223d2f32", 266 | "callback_url" => "https://webhook.site/5f9a659a-11a2-4925-89cf-8a59ea6a019a", 267 | "bulk_data" => [ 268 | { 269 | "country" => "NG", 270 | "customer" => "+23490803840303", 271 | "amount" => 500, 272 | "recurrence" => "WEEKLY", 273 | "type" => "AIRTIME", 274 | "reference" => "930049200929" 275 | }, 276 | { 277 | "country" => "NG", 278 | "customer" => "+23490803840304", 279 | "amount" =>500, 280 | "recurrence" => "ONCE", 281 | "type": "AIRTIME", 282 | "reference" => "930004912332" 283 | } 284 | ] 285 | } 286 | 287 | response = bill.create_bulk_bill_payments(payload) 288 | print response 289 | 290 | 291 | #get the status of a bill payment 292 | response = bill.get_status_of_a_bill_payment("BPUSSD1591303717500102") 293 | print response 294 | 295 | #get billers categories 296 | response = bill.get_bill_categories 297 | print response 298 | ``` 299 | 300 | ## BankTransfer.new(payment) 301 | #### Its functions includes: 302 | 303 | - .initiate_charge 304 | - .verify_charge 305 | 306 | ## See full flow below 307 | 308 | ```ruby 309 | 310 | require './flutterwave_sdk' 311 | 312 | # This is a FLutterwave object which is expecting public, secret and encrption keys 313 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxxx-X", "FLWSECK-xxxxxxxxx-X", "xxxxxxxxxxx") 314 | 315 | payload = { 316 | "tx_ref" => "MC-158523095056793", 317 | "amount" => "1500", 318 | "email" => "xxxxxxxxx@gmail.com", 319 | "phone_number" => "054709929220", 320 | "currency" => "NGN", 321 | "duration" => 2, 322 | "frequency" => 5, 323 | "narration" => "All star college salary for May", 324 | "is_permanent" => 1 325 | } 326 | 327 | bank_transfer = BankTransfer.new(payment) 328 | 329 | response = bank_transfer.initiate_charge(payload) 330 | 331 | print response 332 | 333 | # verify transaction 334 | response = bank_transfer.verify_charge(response["data"]["tx_ref"]) 335 | 336 | print response 337 | ``` 338 | 339 | ## Beneficiaries.new(payment) 340 | #### Its functions includes: 341 | 342 | - .create_beneficiary 343 | - .list_beneficiaries 344 | - .fetch_beneficiary 345 | - .delete_beneficiary 346 | 347 | ## See full flow below 348 | 349 | ```ruby 350 | require './flutterwave_sdk' 351 | 352 | # This is a Flutterwave object which is expecting public, secret and encrption keys 353 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxxx-X", "FLWSECK-xxxxxxxx-X", "xxxxxxxxxx") 354 | Beneficiary = Beneficiaries.new(payment) 355 | 356 | #create a beneficiary 357 | payload = { 358 | "account_number" => "0690000032", 359 | "account_bank" => "044" 360 | } 361 | 362 | response = Beneficiary.create_beneficiary(payload) 363 | print response 364 | 365 | #list beneficiaries 366 | 367 | response = Beneficiary.list_beneficiaries 368 | 369 | print response 370 | 371 | 372 | #fetch beneficiary 373 | response = Beneficiary.fetch_beneficiary(7369) 374 | print response 375 | 376 | 377 | #delete beneficiary 378 | response = Beneficiary.delete_beneficiary(7369) 379 | print response 380 | 381 | ``` 382 | 383 | ## USSD.new(payment) 384 | #### Its functions includes: 385 | 386 | - .initiate_charge 387 | - .verify_charge 388 | 389 | ## See full flow below 390 | 391 | ```ruby 392 | 393 | require './flutterwave_sdk' 394 | 395 | # This is a Flutterwave object which is expecting public, secret and encrption keys 396 | payment = Flutterwave.new("FLWPUBK-xxxxxxx-X", "FLWSECK-xxxxxxx-X", "xxxxxx") 397 | 398 | payload = { 399 | "tx_ref" => "MC-15852309v5050w34", 400 | "account_bank" => "044", 401 | "amount" => "1500", 402 | "currency" => "NGN", 403 | "email" => "xxxxxxxxxxxxx@gmail.com", 404 | "phone_number" => "054709929220", 405 | "fullname" => "Test Name" 406 | 407 | } 408 | 409 | ussd = USSD.new(payment) 410 | 411 | response = ussd.initiate_charge(payload) 412 | print response 413 | 414 | 415 | # verify transactioin with the id 416 | response = ussd.verify_charge(283516336) 417 | print response 418 | 419 | ``` 420 | 421 | ## Transfer.new(payment) 422 | #### Its functions includes: 423 | 424 | - .transfer_fee 425 | - .initiate_transfer 426 | - .initiate_bulk_transfer 427 | - .get_all_transfers 428 | - .get_a_transfer 429 | 430 | ## See full flow below 431 | 432 | ```ruby 433 | 434 | 435 | require './flutterwave_sdk' 436 | 437 | # This is a Flutterwave object which is expecting public, secret and encrption keys 438 | payment = Flutterwave.new("FLWPUBK-xxxxxxx-X", "FLWSECK-xxxxxxx-X", "xxxxxxxxx") 439 | 440 | transfer = Transfer.new(payment) 441 | payload = { 442 | "account_bank" => "044", 443 | "account_number" => "0690000040", 444 | "amount" => 5000, 445 | "narration" => "Akhlm Pstmn Trnsfr xx007", 446 | "currency" => "NGN", 447 | "reference" => "eightm-pstmnpyt-rfxx007_P0MCKDU_1", 448 | "callback_url" => "https://webhook.site/b3e505b0-fe02-430e-a538-22bbbce8ce0d", 449 | "debit_currency" => "NGN" 450 | } 451 | 452 | response = transfer.initiate_transfer(payload) 453 | print response 454 | 455 | 456 | # get transfer fee 457 | currency = "NGN" 458 | amount = "5000" 459 | response = transfer.transfer_fee(currency, amount) 460 | print response 461 | 462 | #get all transfers 463 | response = transfer.get_all_transfers 464 | print response 465 | 466 | #get a transfer 467 | response = transfer.get_a_transfer(125445) 468 | print response 469 | 470 | ``` 471 | 472 | ## VirtualCard.new(payment) 473 | #### Its functions includes: 474 | 475 | - .create_virtual_card 476 | - .get_all_virtual_cards 477 | - .get_virtual_card 478 | - .fund_virtual_card 479 | - .terminate_virtual_card 480 | - .get_virtual_card_transactions 481 | - .withdraw_from_virtual_card 482 | - .block_unblock_virtual_card 483 | 484 | 485 | ## See full flow below 486 | 487 | ```ruby 488 | 489 | require './flutterwave_sdk' 490 | 491 | # This is a Flutterwave object which is expecting public, secret and encrption keys 492 | payment = Flutterwave.new("FLWPUBK_TEST-xxxxxxxx-X", "FLWSECK_TEST-xxxxxx-X", "xxxxxxxxx") 493 | virtual_card = VirtualCard.new(payment) 494 | 495 | 496 | create virtual card 497 | payload = {"currency" => "NGN", 498 | "amount" => 20000, 499 | "billing_name" => "Test Name", 500 | "billing_address" => "2014 Forest Hills Drive", 501 | "billing_city" => "Node", 502 | "billing_state" => "Javascript", 503 | "billing_postal_code" => "000009", 504 | "billing_country" => "NG", 505 | "callback_url" => "https://your-callback-url.com/" 506 | } 507 | 508 | response = virtual_card.create_virtual_card(payload) 509 | 510 | print response 511 | 512 | 513 | #get all virtual cards 514 | response = virtual_card.get_all_virtual_cards 515 | print response 516 | 517 | 518 | #get a virtual card 519 | response = virtual_card.get_virtual_card("594715a6-ae77-483c-811e-19057aedacff") 520 | print response 521 | 522 | 523 | #fund a virtual card 524 | payload = { 525 | "debit_currency" => "NGN", 526 | "amount" => 4000 527 | } 528 | 529 | id = "594715a6-ae77-483c-811e-19057aedacff" 530 | response = virtual_card.fund_virtual_card(id, payload) 531 | print response 532 | 533 | #get virtual card transactions 534 | from = "2019-01-01" 535 | to = "2020-01-13" 536 | index = 0 537 | size = 1 538 | 539 | response = virtual_card.get_virtual_card_transactions("594715a6-ae77-483c-811e-19057aedacff", from, to, index, size) 540 | 541 | 542 | #withdraw from a virtual card 543 | payload = { 544 | "amount" => "1000" 545 | } 546 | 547 | id = "594715a6-ae77-483c-811e-19057aedacff" 548 | 549 | response = virtual_card.withdraw_from_virtual_card(id,payload) 550 | print response 551 | 552 | #block/unblock virtualcard 553 | id = "594715a6-ae77-483c-811e-19057aedacff" 554 | status_action = "unblock" 555 | response = virtual_card.block_unblock_virtual_card(id,status_action) 556 | print response 557 | 558 | ``` 559 | 560 | ## TokenizedCharge.new(payment) 561 | #### Its functions includes: 562 | 563 | - .tokenized_charge 564 | - .verify_tokenized_charge 565 | - .update_token 566 | - .bulk_tokenized_charge 567 | - .bulk_tokenized_charge_status 568 | - .bulk_tokenized_charge_transactions 569 | 570 | ## See full flow below 571 | 572 | ```ruby 573 | require './flutterwave_sdk' 574 | 575 | # This is a Flutterwave object which is expecting public, secret and encrption keys 576 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxxxx-X", "FLWSECK-xxxxxxxxxx-X", "xxxxxxxxxxxxx") 577 | 578 | # This is used to perform card charge 579 | payload = { 580 | "token" => "flw-t1nf-264db944ee46d0a2627573a496f5432c-m03k", 581 | "currency" => "NGN", 582 | "country" => "NG", 583 | "amount" => "10", 584 | "email" => "user@example.com", 585 | "first_name" => "Test", 586 | "last_name" => "Name", 587 | "ip" => "pstmn", 588 | "narration" => "testing charge with token" 589 | } 590 | 591 | charge_with_token = TokenizedCharge.new(payment) 592 | response = charge_with_token.tokenized_charge(payload) 593 | print response 594 | 595 | # Verify tokenized transaction 596 | response = charge_with_token.verify_tokenized_charge(response["data"]["tx_ref"]) 597 | print response 598 | 599 | 600 | #update token 601 | payload = { 602 | "email" => "user@example.com", 603 | "first_name" => "Test", 604 | "last_name" => "Name", 605 | "phone_number" => "09000000000000" 606 | } 607 | charge_with_token = TokenizedCharge.new(payment) 608 | 609 | token = "flw-t1nf-264db944ee46d0a2627573a496f5432c-m03k" 610 | 611 | response = charge_with_token.update_token(payload, token) 612 | print response 613 | 614 | 615 | #bulk tokenized charge 616 | 617 | payload = { 618 | "title" => "test", 619 | "retry_strategy" => { 620 | "retry_interval" => 120, 621 | "retry_amount_variable" => 60, 622 | "retry_attempt_variable" => 2, 623 | }, 624 | "bulk_data" => [ 625 | { 626 | "token" => "flw-t1nf-264db944ee46d0a2627573a496f5432c-m03k", 627 | "currency" => "NGN", 628 | "country" => "NG", 629 | "amount" => "10", 630 | "email" => "user@example.com", 631 | "first_name" => "Test", 632 | "last_name" => "Name", 633 | "ip" => "pstmn", 634 | "narration" => "testing charge with token", 635 | }, 636 | { 637 | "token" => "flw-t1nf-264db944ee46d0a2627573a496f5432c-m03k", 638 | "currency" => "NGN", 639 | "country" => "NG", 640 | "amount" => "10", 641 | "email" => "user@example.com", 642 | "first_name" => "Test", 643 | "last_name" => "Name", 644 | "ip" => "pstmn", 645 | "narration" => "testing charge with token" 646 | } 647 | ] 648 | } 649 | 650 | charge_with_token = TokenizedCharge.new(payment) 651 | response = charge_with_token.bulk_tokenized_charge(payload) 652 | 653 | print response 654 | 655 | 656 | #get status of bulk tokenized charges 657 | id = 175 658 | charge_with_token = TokenizedCharge.new(payment) 659 | response = charge_with_token.bulk_tokenized_charge_status(id) 660 | print response 661 | 662 | 663 | #fetch bulk tokenized transactions 664 | id = 175 665 | charge_with_token = TokenizedCharge.new(payment) 666 | response = charge_with_token.bulk_tokenized_charge_transactions(id) 667 | print response 668 | 669 | ``` 670 | 671 | ## Settlements.new(payment) 672 | #### Its functions includes: 673 | 674 | - .get_settlements 675 | - .get_settlement 676 | 677 | ## See full flow below 678 | 679 | ```ruby 680 | require './flutterwave_sdk' 681 | 682 | # This is a Flutterwave object which is expecting public, secret and encrption keys 683 | payment = Flutterwave.new("FLWPUBK_TEST-xxxxxxxxx-X", "FLWSECK_TEST-xxxxxxxxxx-X", "xxxxxxxxxxxxx") 684 | settlement = Settlements.new(payment) 685 | 686 | 687 | # get all settlements 688 | response = settlement.get_settlements 689 | print response 690 | 691 | 692 | #get a settlment 693 | response =settlement.get_settlement(63016) 694 | print response 695 | 696 | ``` 697 | 698 | ## QR.new(payment) 699 | #### Its functions includes: 700 | 701 | - .initiate_charge 702 | - .verify_charge 703 | 704 | ## See full flow below 705 | 706 | ```ruby 707 | 708 | require './flutterwave_sdk' 709 | 710 | # This is a FLutterwave object which is expecting public, secret and encrption keys 711 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxxx-X", "FLWSECK-xxxxxxxxxxxxxxx-X", "xxxxxxxxxxxxxxxx") 712 | 713 | payload = { 714 | "tx_ref" => "MC-15852309v5050w34", 715 | "amount" => "1500", 716 | "currency" => "NGN", 717 | "email" => "xxxxxxxxxxxx@gmail.com", 718 | "phone_number" => "090000000000", 719 | "fullname" => "Test name" 720 | 721 | } 722 | 723 | qr = QR.new(payment) 724 | 725 | response = qr.initiate_charge(payload) 726 | print response 727 | 728 | # verify QR transaction 729 | response = qr.verify_charge(response["data"]["tx_ref"]) 730 | print response 731 | 732 | ``` 733 | 734 | ## Transactions.new(payment) 735 | #### Its functions includes: 736 | 737 | - .transaction_fee 738 | - .get_transactions 739 | - .verify_transaction 740 | - .transactions_events 741 | - .initiate_a_refund 742 | - .resend_transaction_webhook 743 | 744 | ## see full flow below 745 | 746 | ```ruby 747 | 748 | require './flutterwave_sdk' 749 | 750 | # This is a Flutterwave object which is expecting public, secret and encrption keys 751 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxxx-X", "FLWSECK-xxxxxxxxxxxxxxxxxx-X", "xxxxxxxxxxxxxxx") 752 | 753 | fee = Transactions.new(payment) 754 | currency = "NGN" 755 | amount = "1000" 756 | response = fee.transaction_fee(currency, amount) 757 | print response 758 | 759 | 760 | # get Transactions 761 | fee = Transactions.new(payment) 762 | response = fee.get_transactions 763 | print response 764 | 765 | # get transaction events 766 | fee = Transactions.new(payment) 767 | response = fee.transactions_events(1321548) 768 | print response 769 | 770 | # initiate a refund 771 | payload = { 772 | "amount" => "5" 773 | } 774 | # id = 1321548 775 | fee = Transactions.new(payment) 776 | response = fee.initiate_a_refund(payload, 1321548) 777 | print response 778 | 779 | #resend transaction webhook 780 | payload = { 781 | "id" => 1321548 782 | } 783 | fee = Transactions.new(payment) 784 | response = fee.resend_transactions_webhook(payload) 785 | print response 786 | 787 | ``` 788 | 789 | ## VirtualAccountNumber.new(payment) 790 | #### Its functions includes: 791 | 792 | - .create_virtual_account_number 793 | - .create_bulk_virtual_account_number 794 | - .get_bulk_virtual_account_number 795 | - .get_virtual_account_number 796 | 797 | # see full flow below 798 | 799 | ```ruby 800 | 801 | require './flutterwave_sdk' 802 | 803 | # This is a Flutterwave object which is expecting public, secret and encrption keys 804 | payment = Flutterwave.new("FLWPUBK_TEST-xxxxxxxx-X", "FLWSECK_TEST-xxxxxxxxxx-X", "xxxxxxxxx") 805 | account_number = VirtualAccountNumber.new(payment) 806 | 807 | 808 | # #create virtual account number 809 | payload = { 810 | "email" => "xxxxxxxxxx@gmail.com", 811 | "duration" => 5, 812 | "frequency" => 5, 813 | "is_permanent" => true, 814 | "tx_ref" => "jhn-Test-10192029920" 815 | } 816 | 817 | response = account_number.create_virtual_account_number(payload) 818 | print response 819 | 820 | #bulk account number 821 | payload = { 822 | "email" => "xxxxxxxxx@gmail.com", 823 | "duration" => 5, 824 | "accounts" => 5, 825 | "is_permanent" => true, 826 | "tx_ref" => "jhn-Test-10192029920" 827 | } 828 | 829 | response = account_number.create_bulk_virtual_account_number(payload) 830 | print response 831 | 832 | 833 | # get bulk virtual account number 834 | response = account_number.get_bulk_virtual_account_number("-RND_1071591303048505") 835 | print response 836 | 837 | # Get a virtual account number 838 | response = account_number.get_virtual_account_number("URF_1591302653177_6055335") 839 | print response 840 | 841 | ``` 842 | 843 | ## Subscriptions.new(payment) 844 | #### Its functions includes: 845 | 846 | - .get_all_subscriptions 847 | - .cancel_subscription 848 | - .activate_subscription 849 | 850 | # see full flow below 851 | 852 | ```ruby 853 | require './flutterwave_sdk' 854 | 855 | # This is a Flutterwave object which is expecting public, secret and encrption keys 856 | payment = Flutterwave.new("FLWPUBK-xxxxxxxx-X", "FLWSECK-xxxxxxxxxx-X", "xxxxxxxxxxx") 857 | subscription = Subscriptions.new(payment) 858 | 859 | #get all subscriptions 860 | response = subscription.get_all_subscriptions 861 | print response 862 | 863 | #cancel subscription 864 | response = subscription.cancel_subscription(247490) 865 | print response 866 | 867 | #activate subcription 868 | response = subscription.activate_subscription(247490) 869 | print response 870 | 871 | ``` 872 | 873 | ## OTP.new(payment) 874 | #### Its functions includes: 875 | 876 | - .create_otp 877 | - .validate_otp 878 | 879 | # see full flow below 880 | 881 | ```ruby 882 | require './flutterwave_sdk' 883 | 884 | # This is a Flutterwave object which is expecting public, secret and encrption keys 885 | payment = Flutterwave.new("FLWPUBK_TEST-xxxxxxxxxxxxxx-X", "FLWSECK_TEST-xxxxxxxxxxxx-X", "xxxxxxxxx") 886 | otp = OTP.new(payment) 887 | 888 | payload = { 889 | "length" => 7, 890 | "customer" => { "name" => "Test", "email" => "xxxxxxxxxxx@gmail.com", "phone" => "2348131149273" }, 891 | "sender" => "Test Name", 892 | "send" => true, 893 | "medium" => ["email", "whatsapp"], 894 | "expiry" => 5 895 | } 896 | 897 | response = otp.create_otp(payload) 898 | print response 899 | 900 | #validate otp 901 | payload = { 902 | "otp" => 481208 903 | } 904 | 905 | reference = "CF-BARTER-20190420022611377491" 906 | response = otp.validate_otp(reference, payload) 907 | print response 908 | 909 | ``` 910 | 911 | ## Subaccount.new(payment) 912 | #### Its functions includes: 913 | 914 | - .create_subaccount 915 | - .fetch_subaccounts 916 | - .fetch_subaccount 917 | - .update_subaccount 918 | - .delete_subaccount 919 | 920 | ## see full flow below 921 | 922 | ```ruby 923 | require './flutterwave_sdk' 924 | 925 | # This is a Flutterwave object which is expecting public, secret and encrption keys 926 | payment = Flutterwave.new("FLWPUBK_TEST-xxxxxxxx-X", "FLWSECK_TEST-xxxxxxxx-X", "xxxxxx") 927 | subaccount = Subaccount.new(payment) 928 | 929 | #create subaccount 930 | payload = { 931 | "account_bank" => "044", 932 | "account_number" => "0690000036", 933 | "business_name" => "Test Name", 934 | "business_email" => "xxxxxx@gmail.com", 935 | "business_contact" => "Anonymous", 936 | "business_contact_mobile" => "090890382", 937 | "business_mobile" => "09087930450", 938 | "country" => "NG", 939 | "split_type" => "percentage", 940 | "split_value" => 0.5 941 | } 942 | 943 | reponse = subaccount.create_subaccount(payload) 944 | print reponse 945 | 946 | #fetch all subaccounts 947 | reponse = subaccount.fetch_subaccounts 948 | print reponse 949 | 950 | 951 | #fetch a sub account 952 | reponse = subaccount.fetch_subaccount(5740) 953 | print reponse 954 | 955 | 956 | #update subaccount 957 | payload = { 958 | "business_email" => "xxxxx@gmail.com" 959 | } 960 | id = 5740 961 | reponse = subaccount.update_subaccount(id, payload) 962 | print reponse 963 | 964 | 965 | #delete subaccount 966 | reponse = subaccount.delete_subaccount(5740) 967 | print reponse 968 | 969 | ``` 970 | 971 | ## PaymentPlan.new(payment) 972 | #### Its functions includes: 973 | 974 | - .create_payment_plan 975 | - .get_payment_plans 976 | - .get_a_payment_plan 977 | - .update_payment_plan 978 | - .cancel_payment_plan 979 | 980 | ## see full flow below 981 | 982 | ```ruby 983 | require './flutterwave_sdk' 984 | 985 | # This is a Flutterwave object which is expecting public, secret and encrption keys 986 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxx-X", "FLWSECK-xxxxxxxxxx-X", "xxxxxxxxxxxxx") 987 | payment_plan = PaymentPlan.new(payment) 988 | 989 | #create payment plan 990 | payload = { 991 | "amount" => 5000, 992 | "name" => "the akhlm postman plan 2", 993 | "interval" => "monthly", 994 | "duration" => 48 995 | } 996 | 997 | response = payment_plan.create_payment_plan(payload) 998 | print response 999 | 1000 | 1001 | #get payment plans 1002 | response = payment_plan.get_payment_plans 1003 | print response 1004 | 1005 | #get a payment plan 1006 | response = payment_plan.get_a_payment_plan(5981) 1007 | print response 1008 | 1009 | #update a payment plan 1010 | payload = { 1011 | "name" => "Test name", 1012 | "status" => "active" 1013 | } 1014 | 1015 | response = payment_plan.update_payment_plan(5981, payload) 1016 | print response 1017 | 1018 | #cancel payment plan 1019 | response = payment_plan.cancel_payment_plan(5981) 1020 | print response 1021 | 1022 | ``` 1023 | 1024 | ## MobileMoney.new(payment) 1025 | #### Its functions includes: 1026 | 1027 | - .initiate_charge 1028 | - .verify_charge 1029 | 1030 | ## see full flow below 1031 | 1032 | ```ruby 1033 | require './flutterwave_sdk' 1034 | 1035 | # This is a Flutterwave object which is expecting public, secret and encrption keys 1036 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxxxxxxx-X", "FLWSECK-xxxxxxxxxxxx-X", "xxxxxxxxxx") 1037 | 1038 | # This is used to perform Mpesa transaction 1039 | payload = { 1040 | "tx_ref" => "khlm-158943942o3", 1041 | "amount" => "50", 1042 | "currency" => "KES", 1043 | "email" => "johnmadakin@gmail.com", 1044 | "phone_number" => "054709929220", 1045 | "fullname" => "John Madakin", 1046 | "client_ip" => "154.123.220.1", 1047 | "device_fingerprint" => "62wd23423rq32dskd4323qew1" 1048 | 1049 | } 1050 | 1051 | charge_mpesa = MobileMoney.new(payment) 1052 | 1053 | response = charge_mpesa.initiate_charge(payload) 1054 | print response 1055 | 1056 | #verify transaction 1057 | response = charge_mpesa.verify_charge(response["data"]["tx_ref"]) 1058 | print response 1059 | 1060 | 1061 | #zambia test 1062 | 1063 | payload = { 1064 | "tx_ref" => "MC-158523s09v5050e8", 1065 | "amount" => "1500", 1066 | "currency" => "ZMW", 1067 | "network" => "MTN", 1068 | "email" => "xxxxxxxxxx@gmail.com", 1069 | "phone_number" => "054709929220", 1070 | "fullname" => "Test Name" 1071 | } 1072 | 1073 | charge_zambia = MobileMoney.new(payment) 1074 | 1075 | response = charge_zambia.initiate_charge(payload) 1076 | print response 1077 | 1078 | #verify transaction 1079 | response = charge_zambia.verify_charge(response["data"]["tx_ref"]) 1080 | print response 1081 | 1082 | 1083 | # # Ghana mobile money test 1084 | payload = { 1085 | "tx_ref" => "MC-158523s09v5050e8", 1086 | "amount" => "150", 1087 | "currency" => "GHS", 1088 | "voucher" => "143256743", 1089 | "network" => "MTN", 1090 | "email" => "xxxxx@gmail.com", 1091 | "phone_number" => "054709929220", 1092 | "fullname": "Test Name" 1093 | } 1094 | 1095 | charge_ghana = MobileMoney.new(payment) 1096 | 1097 | #initiate transaction 1098 | response = charge_ghana.initiate_charge(payload) 1099 | print response 1100 | 1101 | #verify transaction 1102 | response = charge_ghana.verify_charge(response["data"]["tx_ref"]) 1103 | print response 1104 | 1105 | 1106 | # Rwanda mobile money test 1107 | 1108 | payload = { 1109 | "tx_ref" => "MC-158523s09v5050e8", 1110 | "amount" => "1500", 1111 | "currency" => "RWF", 1112 | "network" => "MTN", 1113 | "email" => "xxxxx@gmail.com", 1114 | "phone_number" => "054709929220", 1115 | "fullname" => "Test Name" 1116 | } 1117 | 1118 | charge_rwanda = MobileMoney.new(payment) 1119 | 1120 | response = charge_rwanda.initiate_charge(payload) 1121 | print response 1122 | 1123 | # verify transaction 1124 | response = charge_rwanda.verify_charge(response["data"]["tx_ref"]) 1125 | print response 1126 | 1127 | 1128 | #uganda test 1129 | 1130 | payload = { 1131 | "tx_ref" => "MC-1585230950500", 1132 | "amount" => "1500", 1133 | "email" => "xxxxxxxx@gmail.com", 1134 | "phone_number" => "054709929220", 1135 | "currency" => "UGX", 1136 | "redirect_url" => "https://rave-webhook.herokuapp.com/receivepayment", 1137 | "network" => "MTN" 1138 | 1139 | } 1140 | 1141 | charge_uganda = MobileMoney.new(payment) 1142 | 1143 | response = charge_uganda.initiate_charge(payload) 1144 | print response 1145 | 1146 | response = charge_uganda.verify_charge(response["data"]["tx_ref"]) 1147 | print response 1148 | 1149 | # franco phone 1150 | payload = { 1151 | "tx_ref" => "MC-1585230950501", 1152 | "amount" => "1500", 1153 | "email" => "xxxxxx@gmail.com", 1154 | "phone_number" => "054709929220", 1155 | "currency" => "XAF", 1156 | "redirect_url" => "https://rave-webhook.herokuapp.com/receivepayment" 1157 | 1158 | } 1159 | 1160 | charge_franco = MobileMoney.new(payment) 1161 | 1162 | response = charge_franco.initiate_charge(payload) 1163 | print response 1164 | 1165 | 1166 | response = charge_franco.verify_charge(response["data"]["tx_ref"]) 1167 | print response 1168 | ``` 1169 | 1170 | ## Misc.new(payment) 1171 | #### Its functions includes: 1172 | 1173 | _ .get_all_wallet_balance 1174 | - .get_balance_per_currency 1175 | - .resolve_account 1176 | - .resolve_bvn 1177 | - .resolve_card_bin 1178 | 1179 | ## see full flow below 1180 | 1181 | ```ruby 1182 | require './flutterwave_sdk' 1183 | 1184 | # This is a Flutterwave object which is expecting public, secret and encrption keys 1185 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxxx-X", "FLWSECK-xxxxx-X", "xxxxxxxxxxxxxxx") 1186 | misc = Misc.new(payment) 1187 | 1188 | #get all wallet balance 1189 | response = misc.get_all_wallet_balance 1190 | print response 1191 | 1192 | 1193 | #get balance per cuurency 1194 | response = misc.get_balance_per_currency("NGN") 1195 | print response 1196 | 1197 | #resolve account 1198 | payload = { 1199 | "account_number" => "0690000032", 1200 | "account_bank" => "044" 1201 | } 1202 | response = misc.resolve_account(payload) 1203 | 1204 | print response 1205 | 1206 | #resolve bvn 1207 | response = misc.resolve_bvn("12345678901") 1208 | print response 1209 | 1210 | 1211 | #resolve card bin 1212 | response = misc.resolve_card_bin(553188) 1213 | print response 1214 | 1215 | ``` 1216 | 1217 | ## Preauth.new(payment) 1218 | #### Its functions includes: 1219 | 1220 | - .capture_preauth 1221 | - .void_preauth 1222 | - .refund_preauth 1223 | 1224 | ## see full flow below 1225 | 1226 | ```ruby 1227 | require './flutterwave_sdk' 1228 | 1229 | # This is a Flutterwave object which is expecting public, secret and encrption keys 1230 | payment = Flutterwave.new("FLWPUBK-xxxxxxxxx-X", "xxxxxxxxxxxxxx", "xxxxxxxxxxxxxx") 1231 | 1232 | # This is used to perform preauth capture 1233 | 1234 | auth = Preauth.new(payment) 1235 | 1236 | payload = { 1237 | "amount" => "50" 1238 | } 1239 | 1240 | flw_ref = "FLW-MOCK-d6b76a67a639dc124917b8957baa5278" 1241 | 1242 | repsonse = auth.capture_preauth(flw_ref, payload) 1243 | print response 1244 | 1245 | 1246 | #Void 1247 | response = auth.void_preauth(flw_ref) 1248 | print response 1249 | 1250 | 1251 | #Refund 1252 | payload = { 1253 | "amount" => "30" 1254 | } 1255 | 1256 | flw_ref = "FLW-MOCK-d6b76a67a639dc124917b8957baa5278" 1257 | 1258 | response = auth.refund_preauth(flw_ref, payload) 1259 | print response 1260 | 1261 | 1262 | ``` 1263 | 1264 | 1265 | ## Development 1266 | 1267 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 1268 | 1269 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 1270 | 1271 | ## Contributing 1272 | 1273 | Bug reports and pull requests are welcome on GitHub at https://github.com/Iphytech/flutterwave_sdk. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/Iphytech/flutterwave_sdk/blob/master/CODE_OF_CONDUCT.md). 1274 | 1275 | 1276 | ## License 1277 | 1278 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 1279 | 1280 | ## Code of Conduct 1281 | 1282 | Everyone interacting in the FlutterwaveSdk project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Iphytech/flutterwave_sdk/blob/master/CODE_OF_CONDUCT.md). 1283 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "flutterwave_sdk" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.1.1] - 2023-07-20 4 | ### Added 5 | - Test suite for mobile money TZS transactions. 6 | - Workflow scripts for review and publish 7 | 8 | ### Fixed 9 | - Fix test suite for card. 10 | 11 | 12 | ## [0.1.1] - 2022-06-02 13 | ### Added 14 | - Test suite for mobile money transactions. 15 | - Test suite for transaction fees. 16 | 17 | ### Changed 18 | - Bump package version to 0.1.1 19 | - URL declaration for verifying mobile money payments. 20 | 21 | ### Removed 22 | - Parameter check for currency and amount in the transaction fee method. 23 | 24 | ### Fixed 25 | - Fix NameError for undefined data variable in the transaction fee method. 26 | - Fix NameError for undefined URL in mobile money verify method. 27 | -------------------------------------------------------------------------------- /flutterwave_sdk.gemspec: -------------------------------------------------------------------------------- 1 | require_relative 'lib/flutterwave_sdk/version' 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = "flutterwave_sdk" 5 | spec.version = FlutterwaveSdk::VERSION 6 | spec.authors = ["Flutterwave Developers"] 7 | spec.email = ["developers@flutterwavego.com"] 8 | 9 | spec.date = '2020-05-10' 10 | spec.summary = %q{Official Ruby Gem For Flutterwave APIs.} 11 | spec.description = %q{This is the official Ruby Gem For Flutterwave Payments which includes Card, Account, Transfer, Subaccount, Subscription, Mpesa, Ghana Mobile Money, Ussd, Payment Plans, and Transfer payment methods.} 12 | spec.homepage = "https://github.com/Flutterwave/Flutterwave-Ruby-v3" 13 | spec.license = "MIT" 14 | spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0") 15 | 16 | spec.metadata["homepage_uri"] = "https://developer.flutterwave.com" 17 | spec.metadata["source_code_uri"] = spec.homepage 18 | spec.metadata["changelog_uri"] = "https://github.com/Flutterwave/Flutterwave-Ruby-v3/blob/master/changelog.md" 19 | 20 | # Specify which files should be added to the gem when it is released. 21 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 22 | spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do 23 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 24 | end 25 | spec.bindir = "exe" 26 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 27 | spec.require_paths = ["lib"] 28 | 29 | spec.add_development_dependency "bundler", "~> 2.1.4" 30 | #add dotenv 31 | spec.add_development_dependency "dotenv", "~> 2.8.1" 32 | 33 | # Dependencies 34 | spec.required_ruby_version = ">= 2.5.3" 35 | spec.add_runtime_dependency 'httparty', '~> 0.16.3' 36 | end 37 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk.rb: -------------------------------------------------------------------------------- 1 | require_relative "flutterwave_sdk/version" 2 | require_relative "flutterwave_sdk/flutterwave_modules/base_endpoints" 3 | require_relative "flutterwave_sdk/flutterwave_objects/base/base" 4 | require_relative "flutterwave_sdk/flutterwave_modules/util" 5 | require_relative "flutterwave_sdk/flutterwave_objects/card" 6 | require_relative "flutterwave_sdk/flutterwave_objects/mobile_money" 7 | require_relative "flutterwave_sdk/flutterwave_objects/account_payment" 8 | require_relative "flutterwave_sdk/flutterwave_objects/bank_transfer" 9 | require_relative "flutterwave_sdk/flutterwave_objects/ussd_payment" 10 | require_relative "flutterwave_sdk/flutterwave_objects/qr" 11 | require_relative "flutterwave_sdk/flutterwave_objects/tokenized_charge" 12 | require_relative "flutterwave_sdk/flutterwave_objects/transactions" 13 | require_relative "flutterwave_sdk/flutterwave_objects/transfer" 14 | require_relative "flutterwave_sdk/flutterwave_objects/bank" 15 | require_relative "flutterwave_sdk/flutterwave_objects/misc" 16 | require_relative "flutterwave_sdk/flutterwave_objects/payment_plan" 17 | require_relative "flutterwave_sdk/flutterwave_objects/beneficiaries" 18 | require_relative "flutterwave_sdk/flutterwave_objects/subscriptions" 19 | require_relative "flutterwave_sdk/flutterwave_objects/virtual_card" 20 | require_relative "flutterwave_sdk/flutterwave_objects/subaccount" 21 | require_relative "flutterwave_sdk/flutterwave_objects/settlements" 22 | require_relative "flutterwave_sdk/flutterwave_objects/otp" 23 | require_relative "flutterwave_sdk/flutterwave_objects/virtual_account_number" 24 | require_relative "flutterwave_sdk/flutterwave_objects/bills" 25 | require_relative "flutterwave_sdk/flutterwave_objects/preauthorise" 26 | require_relative "flutterwave_sdk/error" 27 | 28 | class Flutterwave 29 | 30 | attr_accessor :public_key, :secret_key, :encryption_key, :production, :url 31 | 32 | # method to initialize flutterwave object 33 | def initialize(public_key=nil, secret_key=nil, encryption_key=nil, production=false) 34 | @public_key = public_key 35 | @secret_key = secret_key 36 | @production = production 37 | @encryption_key = encryption_key 38 | flutterwave_sandbox_url = BASE_ENDPOINTS::FLUTTERWAVE_SANDBOX_URL 39 | flutterwave_live_url = BASE_ENDPOINTS::FLUTTERWAVE_LIVE_URL 40 | 41 | # set rave url to sandbox or live if we are in production or development 42 | if production == false 43 | @url = flutterwave_sandbox_url 44 | else 45 | @url = flutterwave_live_url 46 | end 47 | 48 | def base_url 49 | return url 50 | end 51 | 52 | # check if we set our public , secret and encryption keys to the environment variable 53 | if (public_key.nil?) 54 | @public_key = ENV['FLUTTERWAVE_PUBLIC_KEY'] 55 | else 56 | @public_key = public_key 57 | end 58 | 59 | if (secret_key.nil?) 60 | @secret_key = ENV['FLUTTERWAVE_SECRET_KEY'] 61 | else 62 | @secret_key = secret_key 63 | end 64 | 65 | if (encryption_key.nil?) 66 | @encryption_key = ENV['FLUTTERWAVE_ENCRYPTION_KEY'] 67 | else 68 | @encryption_key = encryption_key 69 | end 70 | warn "Warning: To ensure your rave account api keys are safe, It is best to always set your keys in the environment variable" 71 | 72 | # raise this error if no public key is passed 73 | unless !@public_key.nil? 74 | raise FlutterwaveBadKeyError, "No public key supplied and couldn't find any in environment variables. Make sure to set public key as an environment variable FLUTTERWAVE_PUBLIC_KEY" 75 | end 76 | # raise this error if invalid public key is passed 77 | unless @public_key[0..7] == 'FLWPUBK-' || @public_key[0..11] == 'FLWPUBK_TEST' 78 | raise FlutterwaveBadKeyError, "Invalid public key #{@public_key}" 79 | end 80 | 81 | # raise this error if no secret key is passed 82 | unless !@secret_key.nil? 83 | raise FlutterwaveBadKeyError, "No secret key supplied and couldn't find any in environment variables. Make sure to set secret key as an environment variable FLUTTERWAVE_SECRET_KEY" 84 | end 85 | # raise this error if invalid secret key is passed 86 | unless @secret_key[0..7] == 'FLWSECK-' || @secret_key[0..11] == 'FLWSECK_TEST' 87 | raise FlutterwaveBadKeyError, "Invalid secret key #{@secret_key}" 88 | end 89 | 90 | # raise this error if no encryption key is passed 91 | unless !@encryption_key.nil? 92 | raise FlutterwaveBadKeyError, "No encryption key supplied and couldn't find any in environment variables. Make sure to set encryption key as an environment variable FLUTTERWAVE_ENCRYPTION_KEY" 93 | end 94 | end 95 | 96 | #tracking activities 97 | def flutterwave_tracking 98 | endpoint = "https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/staging/sendevent" 99 | public_key = @public_key 100 | 101 | 102 | payload = { 103 | "PBFPubKey" => public_key, 104 | "language" => "Ruby", 105 | "version" => "1.0", 106 | "title" => "test message", 107 | "message" => "test is done" 108 | } 109 | data = payload.to_json 110 | 111 | response = HTTParty.post(endpoint, { 112 | body: data, 113 | headers: { 114 | 'Content-Type' => 'application/json' 115 | } 116 | }) 117 | 118 | unless (response.code == 200 || response.code == 201) 119 | raise RaveServerError.new(response), "HTTP Code #{response.code}: #{response.body}" 120 | end 121 | return response 122 | end 123 | 124 | end 125 | 126 | 127 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk/error.rb: -------------------------------------------------------------------------------- 1 | class FlutterwaveServerError < StandardError 2 | attr_reader :response 3 | def initialize(response=nil) 4 | @response = response 5 | end 6 | end 7 | 8 | class FlutterwaveBadKeyError < StandardError 9 | end 10 | 11 | class IncompleteParameterError < StandardError 12 | end 13 | 14 | class SuggestedAuthError < StandardError 15 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_modules/base_endpoints.rb: -------------------------------------------------------------------------------- 1 | module BASE_ENDPOINTS 2 | FLUTTERWAVE_LIVE_URL = "https://api.flutterwave.com/v3" 3 | FLUTTERWAVE_SANDBOX_URL = "https://api.flutterwave.com/v3" 4 | CHARGE_ENDPOINT = "/charges" 5 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_modules/util.rb: -------------------------------------------------------------------------------- 1 | 2 | require "digest" 3 | require "openssl" 4 | require "base64" 5 | require 'json' 6 | require 'securerandom' 7 | 8 | module Util 9 | 10 | # method to generate merchants transaction reference 11 | def self.transaction_reference_generator 12 | transaction_ref = "MC-" + SecureRandom.hex 13 | return transaction_ref 14 | end 15 | 16 | # method for encryption algorithm 17 | def self.encrypt(key, data) 18 | cipher = OpenSSL::Cipher.new("des-ede3") 19 | cipher.encrypt # Call this before setting key 20 | cipher.key = key 21 | data = data.to_json 22 | ciphertext = cipher.update(data) 23 | ciphertext << cipher.final 24 | return Base64.encode64(ciphertext) 25 | end 26 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/account_payment.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class AccountPayment < Base 5 | def initiate_charge(data) 6 | base_url = flutterwave_object.base_url 7 | 8 | # only update the payload with the transaction reference if it isn't already added to the payload 9 | if !data.key?("tx_ref") 10 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 11 | end 12 | # check the currency to determine the type and the required parameters 13 | currency = data["currency"] 14 | if currency == "NGN" 15 | required_parameters = [ "amount", "email", "account_bank", "account_number", "tx_ref", "currency"] 16 | type = "debit_ng_account" 17 | elsif currency == "GBP" 18 | required_parameters = [ "amount", "email", "account_bank", "account_number", "tx_ref", "currency"] 19 | type = "debit_uk_account" 20 | elsif currency == "USD" || currency == "ZAR" 21 | required_parameters = [ "amount", "email", "country", "tx_ref", "currency"] 22 | type = "ach_payment" 23 | else 24 | return "pass a valid currency" 25 | end 26 | 27 | check_passed_parameters(required_parameters, data) 28 | type = type 29 | payload = data.to_json 30 | 31 | response = post_request("#{base_url}#{BASE_ENDPOINTS::CHARGE_ENDPOINT}?type=#{type}", payload) 32 | return response 33 | end 34 | 35 | def validate_charge(flw_ref, otp) 36 | base_url = flutterwave_object.base_url 37 | 38 | payload = { 39 | "otp" => otp, 40 | "flw_ref" => flw_ref 41 | } 42 | 43 | payload = payload.to_json 44 | 45 | response = post_request("#{base_url}/validate-charge", payload) 46 | return response 47 | end 48 | 49 | def verify_charge(id) 50 | base_url = flutterwave_object.base_url 51 | 52 | response = get_request("#{base_url}/transactions/#{id}/verify") 53 | return response 54 | end 55 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/bank.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Bank < Base 5 | 6 | def get_all_banks(country) 7 | base_url = flutterwave_object.base_url 8 | response = get_request("#{base_url}/banks/#{country}") 9 | return response 10 | end 11 | 12 | def get_bank_branch(id) 13 | base_url = flutterwave_object.base_url 14 | response = get_request("#{base_url}/banks/#{id}/branches") 15 | return response 16 | end 17 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/bank_transfer.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class BankTransfer < Base 5 | def initiate_charge(data) 6 | base_url = flutterwave_object.base_url 7 | 8 | # only update the payload with the transaction reference if it isn't already added to the payload 9 | if !data.key?("tx_ref") 10 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 11 | end 12 | # check the currency to determine the type and the required parameters 13 | required_parameters = ["amount", "duration", "email", "phone_number", "frequency", "narration", "is_permanent", "tx_ref", "currency"] 14 | 15 | check_passed_parameters(required_parameters, data) 16 | type = "bank_transfer" 17 | payload = data.to_json 18 | 19 | response = post_request("#{base_url}#{BASE_ENDPOINTS::CHARGE_ENDPOINT}?type=#{type}", payload) 20 | return response 21 | end 22 | 23 | # mthod to verify transaction 24 | def verify_charge(id) 25 | base_url = flutterwave_object.base_url 26 | 27 | response = get_request("#{base_url}/transactions/#{id}/verify") 28 | return response 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/base/base.rb: -------------------------------------------------------------------------------- 1 | require 'httparty' 2 | require_relative "../../flutterwave_modules/base_endpoints" 3 | require "json" 4 | require_relative "../../error" 5 | 6 | class Base 7 | 8 | attr_reader :flutterwave_object 9 | 10 | # method to initialize this class 11 | 12 | def initialize(flutterwave_object=nil) 13 | unless !flutterwave_object.nil? 14 | raise ArgumentError, "Flutterwave Object is required!!!" 15 | end 16 | @flutterwave_object = flutterwave_object 17 | end 18 | 19 | 20 | # method to make a get request 21 | def get_request(endpoint) 22 | # headers = { 23 | # "Authorization" => "Bearer #{flutterwave_object.secret_key}" 24 | # } 25 | begin 26 | response = HTTParty.get(endpoint, :headers => { "Authorization" => "Bearer #{flutterwave_object.secret_key}" }) 27 | unless (response.code == 200 || response.code == 201) 28 | raise FlutterwaveServerError.new(response), "HTTP Code #{response.code}: #{response.body}" 29 | end 30 | 31 | return response 32 | 33 | unless(response.code != 0 ) 34 | raise FlutterwaveServerError.new(response), "Server Message: #{response.message}" 35 | end 36 | 37 | rescue JSON::ParserError => jsonerr 38 | raise FlutterwaveServerError.new(response) , "Invalid result data. Could not parse JSON response body \n #{jsonerr.message}" 39 | return response 40 | end 41 | end 42 | 43 | # method to make a post request 44 | def post_request(endpoint, data) 45 | begin 46 | response = HTTParty.post(endpoint, { 47 | body: data, 48 | headers: { 49 | "Content-Type" => "application/json", 50 | "Authorization" => "Bearer #{flutterwave_object.secret_key}" 51 | } 52 | }) 53 | 54 | unless (response.code == 200 || response.code == 201) 55 | raise FlutterwaveServerError.new(response), "HTTP Code #{response.code}: #{response.body}" 56 | end 57 | return response 58 | end 59 | 60 | end 61 | # method to make a put request 62 | def put_request(endpoint, data) 63 | begin 64 | response = HTTParty.put(endpoint, { 65 | body: data, 66 | headers: { 67 | "Content-Type" => "application/json", 68 | "Authorization" => "Bearer #{flutterwave_object.secret_key}" 69 | } 70 | }) 71 | 72 | unless (response.code == 200 || response.code == 201) 73 | raise FlutterwaveServerError.new(response), "HTTP Code #{response.code}: #{response.body}" 74 | end 75 | return response 76 | end 77 | end 78 | 79 | # method to make a delete request 80 | def delete_request(endpoint, data) 81 | begin 82 | response = HTTParty.delete(endpoint, { 83 | body: data, 84 | headers: { 85 | "Content-Type" => "application/json", 86 | "Authorization" => "Bearer #{flutterwave_object.secret_key}" 87 | } 88 | }) 89 | 90 | unless (response.code == 200 || response.code == 201) 91 | raise FlutterwaveServerError.new(response), "HTTP Code #{response.code}: #{response.body}" 92 | end 93 | return response 94 | end 95 | end 96 | 97 | # method to check if the passed parameters is equal to the expected parameters 98 | def check_passed_parameters(required_params, passed_params) 99 | 100 | # This is used to check if the passed authorization parameters matches the required parameters 101 | required_params.each do |k, v| 102 | if !passed_params.key?(k) 103 | raise IncompleteParameterError, "Parameters Incomplete, Missing Parameter: #{k}, Please pass in the complete parameter." 104 | end 105 | end 106 | end 107 | 108 | end 109 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/base/card_base.rb: -------------------------------------------------------------------------------- 1 | require_relative "base.rb" 2 | 3 | class CardBase < Base 4 | 5 | # method to the passed suggested auth to the corresponding value in the available hash 6 | def get_auth_type(suggested_auth) 7 | auth_map = {"pin" => :pin, "avs_vbvsecurecode" => :address, "noauth_international" => :address, "avs_noauth" => :address} 8 | 9 | # Raise Error if the right authorization type is not passed 10 | unless !auth_map.has_key? auth_map[suggested_auth] 11 | raise RequiredAuthError, "Required suggested authorization type not available." 12 | end 13 | return auth_map[suggested_auth] 14 | end 15 | 16 | 17 | # method to update payload 18 | def update_payload(suggested_auth, payload, **keyword_args) 19 | auth_type = get_auth_type(suggested_auth) 20 | 21 | # Error is raised if the expected suggested auth is not found in the keyword arguments 22 | if !keyword_args.key?(auth_type) 23 | raise SuggestedAuthError, "Please pass the suggested auth." 24 | end 25 | 26 | # if the authorization type is equal to address symbol, update with the required parameters 27 | if auth_type == :address 28 | required_parameters = ["city", "address", "state", "country", "zipcode"] 29 | check_passed_parameters(required_parameters, keyword_args[auth_type]) 30 | authorization = {} 31 | authorization.merge!({"mode" => suggested_auth}) 32 | # puts authorization 33 | authorization.merge!(keyword_args[auth_type]) 34 | payload["authorization"]= authorization 35 | return payload 36 | end 37 | 38 | 39 | # return this updated payload if the passed authorization type isn't address symbol 40 | authorization = {} 41 | # authorization.merge!({"mode" => suggested_auth, "fields" => keyword_args[auth_type]}) 42 | authorization.merge!({"mode" => suggested_auth}) 43 | puts authorization 44 | authorization.merge!(keyword_args[auth_type]) 45 | payload["authorization"]= authorization 46 | return payload 47 | 48 | end 49 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/beneficiaries.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Beneficiaries < Base 5 | 6 | def create_beneficiary(data) 7 | base_url = flutterwave_object.base_url 8 | required_parameters = ["account_number", "account_bank"] 9 | check_passed_parameters(required_parameters, data) 10 | payload = data.to_json 11 | response = post_request("#{base_url}/beneficiaries", payload) 12 | return response 13 | end 14 | 15 | def list_beneficiaries 16 | base_url = flutterwave_object.base_url 17 | response = get_request("#{base_url}/beneficiaries") 18 | return response 19 | end 20 | 21 | def fetch_beneficiary(id) 22 | base_url = flutterwave_object.base_url 23 | response = get_request("#{base_url}/beneficiaries/#{id}") 24 | return response 25 | end 26 | 27 | def delete_beneficiary(id) 28 | base_url = flutterwave_object.base_url 29 | payload = {} 30 | payload = payload.to_json 31 | response = delete_request("#{base_url}/beneficiaries/#{id}", payload) 32 | return response 33 | end 34 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/bills.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Bills < Base 5 | 6 | def create_bill_payment(data) 7 | base_url = flutterwave_object.base_url 8 | required_parameters = ["country", "customer", "amount", "recurrence", "type"] 9 | check_passed_parameters(required_parameters, data) 10 | payload = data.to_json 11 | response = post_request("#{base_url}/bills", payload) 12 | return response 13 | end 14 | 15 | def create_bulk_bill_payments(data) 16 | base_url = flutterwave_object.base_url 17 | required_parameters = ["bulk_reference", "callback_url", "bulk_data"] 18 | check_passed_parameters(required_parameters, data) 19 | payload = data.to_json 20 | response = post_request("#{base_url}/bulk-bills", payload) 21 | return response 22 | end 23 | 24 | def get_status_of_a_bill_payment(reference) 25 | base_url = flutterwave_object.base_url 26 | response = get_request("#{base_url}/bills/#{reference}") 27 | return response 28 | end 29 | 30 | def update_bills_order(reference, data) 31 | base_url = flutterwave_object.base_url 32 | required_parameters = ["bulk_reference", "callback_url", "bulk_data"] 33 | check_passed_parameters(required_parameters, data) 34 | payload = data.to_json 35 | response = post_request("#{base_url}/product-orders/#{reference}", payload) 36 | return response 37 | end 38 | 39 | def validate_bill_service(item_code, data) 40 | base_url = flutterwave_object.base_url 41 | required_parameters = ["code", "customer"] 42 | check_passed_parameters(required_parameters, data) 43 | payload = data.to_json 44 | response = post_request("#{base_url}/bill-items/#{item_code}/validate", payload) 45 | return response 46 | end 47 | 48 | def get_bill_categories 49 | base_url = flutterwave_object.base_url 50 | response = get_request("#{base_url}/bill-categories") 51 | return response 52 | end 53 | 54 | def get_bill_payment_agencies 55 | base_url = flutterwave_object.base_url 56 | response = get_request("#{base_url}/billers") 57 | return response 58 | end 59 | 60 | def get_amount_for_a_product(id, product_id) 61 | base_url = flutterwave_object.base_url 62 | response = get_request("#{base_url}/billers/#{id}/products/#{product_id}") 63 | return response 64 | end 65 | 66 | def get_bill_payments(data) 67 | base_url = flutterwave_object.base_url 68 | payload = data.to_json 69 | response = get_request("#{base_url}/bills", payload) 70 | return response 71 | end 72 | 73 | def get_products_under_an_agency(id) 74 | base_url = flutterwave_object.base_url 75 | response = get_request("#{base_url}/billers/#{id}/products") 76 | return response 77 | end 78 | 79 | def create_order_using_billing_code_and_productid(id, product_id, data) 80 | base_url = flutterwave_object.base_url 81 | payload = data.to_json 82 | response = post_request("#{base_url}/biller/#{id}/products/#{product_id}/orders", payload) 83 | return response 84 | end 85 | 86 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/card.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/card_base.rb" 2 | require 'json' 3 | 4 | class Card < CardBase 5 | 6 | # method to initiate card charge 7 | def initiate_charge(data) 8 | base_url = flutterwave_object.base_url 9 | encryption_key = flutterwave_object.encryption_key 10 | public_key = flutterwave_object.public_key 11 | 12 | # only update the payload with the transaction reference if it isn't already added to the payload 13 | if !data.key?("tx_ref") 14 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 15 | end 16 | 17 | data.merge!({"public_key" => public_key}) 18 | 19 | required_parameters = [ "card_number", "cvv", "expiry_month", "expiry_year", "amount", "tx_ref", "currency", "email"] 20 | check_passed_parameters(required_parameters, data) 21 | 22 | encrypt_data = Util.encrypt(encryption_key, data) 23 | 24 | payload = { 25 | "public_key" => public_key, 26 | "client" => encrypt_data, 27 | "alg" => "3DES-24" 28 | } 29 | type = "card" 30 | payload = payload.to_json 31 | 32 | response = post_request("#{base_url}#{BASE_ENDPOINTS::CHARGE_ENDPOINT}?type=#{type}", payload) 33 | 34 | return response 35 | 36 | end 37 | 38 | def validate_charge(flw_ref, otp) 39 | base_url = flutterwave_object.base_url 40 | payload = { 41 | "otp" => otp, 42 | "flw_ref" => flw_ref 43 | } 44 | 45 | payload = payload.to_json 46 | response = post_request("#{base_url}/validate-charge", payload) 47 | return response 48 | end 49 | 50 | def verify_charge(id) 51 | base_url = flutterwave_object.base_url 52 | response = get_request("#{base_url}/transactions/#{id}/verify") 53 | return response 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/misc.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Misc < Base 5 | def get_all_wallet_balance() 6 | base_url = flutterwave_object.base_url 7 | response = get_request("#{base_url}/balances") 8 | return response 9 | end 10 | 11 | def get_balance_per_currency(currency) 12 | base_url = flutterwave_object.base_url 13 | response = get_request("#{base_url}/balances/#{currency}") 14 | return response 15 | end 16 | 17 | def resolve_account(data) 18 | base_url = flutterwave_object.base_url 19 | required_parameters = ["account_bank", "account_number"] 20 | check_passed_parameters(required_parameters, data) 21 | payload = data.to_json 22 | response = post_request("#{base_url}/accounts/resolve", payload) 23 | return response 24 | end 25 | 26 | def resolve_bvn(bvn) 27 | base_url = flutterwave_object.base_url 28 | response = get_request("#{base_url}/kyc/bvns/#{bvn}") 29 | return response 30 | end 31 | 32 | def resolve_card_bin(bin) 33 | base_url = flutterwave_object.base_url 34 | response = get_request("#{base_url}/card-bins/#{bin}") 35 | return response 36 | end 37 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/mobile_money.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class MobileMoney < Base 5 | def initiate_charge(data) 6 | base_url = flutterwave_object.base_url 7 | 8 | # only update the payload with the transaction reference if it isn't already added to the payload 9 | if !data.key?("tx_ref") 10 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 11 | end 12 | # check the currency to determine the type and the required parameters 13 | if data["currency"] == "KES" 14 | required_parameters = [ "amount", "email", "phone_number", "tx_ref", "currency"] 15 | type = "mpesa" 16 | elsif data["currency"] == "UGX" 17 | required_parameters = ["amount", "email", "phone_number", "tx_ref", "currency"] 18 | type = "mobile_money_uganda" 19 | elsif data["currency"] == "GHS" 20 | required_parameters = ["amount", "email", "phone_number", "tx_ref", "currency"] 21 | type = "mobile_money_ghana" 22 | elsif data["currency"] == "ZMW" 23 | required_parameters = ["amount", "email", "phone_number","tx_ref", "currency"] 24 | type = "mobile_money_zambia" 25 | elsif data["currency"] == "RWF" 26 | required_parameters = ["amount", "email", "phone_number","tx_ref", "currency"] 27 | type = "mobile_money_rwanda" 28 | elsif data["currency"] == "XAF" || data["currency"] == "XOF" 29 | required_parameters = ["amount", "email", "phone_number", "tx_ref", "currency"] 30 | type = "mobile_money_franco" 31 | elsif data["currency"] == "TZS" 32 | required_parameters = ["amount", "email", "phone_number", "tx_ref", "currency"] 33 | type = "mobile_money_tanzania" 34 | else 35 | return "pass a valid currency" 36 | end 37 | 38 | check_passed_parameters(required_parameters, data) 39 | type = type 40 | payload = data.to_json 41 | 42 | response = post_request("#{base_url}#{BASE_ENDPOINTS::CHARGE_ENDPOINT}?type=#{type}", payload) 43 | return response 44 | end 45 | 46 | # mthod to verify transaction 47 | def verify_charge(id) 48 | base_url = flutterwave_object.base_url 49 | 50 | response = get_request("#{base_url}/transactions/#{id}/verify") 51 | return response 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/otp.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class OTP < Base 5 | def create_otp(data) 6 | base_url = flutterwave_object.base_url 7 | required_parameters = ["length", "customer", "sender", "send", "medium"] 8 | check_passed_parameters(required_parameters, data) 9 | payload = data.to_json 10 | response = post_request("#{base_url}/otps", payload) 11 | return response 12 | end 13 | 14 | def validate_otp(reference, data) 15 | base_url = flutterwave_object.base_url 16 | required_parameters = ["otp"] 17 | check_passed_parameters(required_parameters, data) 18 | payload = data.to_json 19 | response = post_request("#{base_url}/otps/#{reference}/validate", payload) 20 | return response 21 | end 22 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/payment_plan.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class PaymentPlan < Base 5 | 6 | # method to create a payment plan 7 | def create_payment_plan(data) 8 | base_url = flutterwave_object.base_url 9 | required_parameters = ["amount", "name", "interval"] 10 | check_passed_parameters(required_parameters, data) 11 | payload = data.to_json 12 | response = post_request("#{base_url}/payment-plans", payload) 13 | return response 14 | end 15 | 16 | def get_payment_plans 17 | base_url = flutterwave_object.base_url 18 | response = get_request("#{base_url}/payment-plans") 19 | return response 20 | end 21 | 22 | def get_a_payment_plan(id) 23 | base_url = flutterwave_object.base_url 24 | response = get_request("#{base_url}/payment-plans/#{id}") 25 | return response 26 | end 27 | 28 | def update_payment_plan(id, data) 29 | base_url = flutterwave_object.base_url 30 | payload = data.to_json 31 | response = put_request("#{base_url}/payment-plans/#{id}",payload) 32 | return response 33 | end 34 | 35 | def cancel_payment_plan(id) 36 | base_url = flutterwave_object.base_url 37 | payload = {} 38 | payload = payload.to_json 39 | response = put_request("#{base_url}/payment-plans/#{id}/cancel",payload) 40 | return response 41 | end 42 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/preauthorise.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Preauth < Base 5 | 6 | def capture_preauth(flw_ref, data) 7 | base_url = flutterwave_object.base_url 8 | payload = data.to_json 9 | response = post_request("#{base_url}/charges/#{flw_ref}/capture", payload) 10 | return response 11 | end 12 | 13 | def void_preauth(flw_ref) 14 | base_url = flutterwave_object.base_url 15 | payload = payload.to_json 16 | response = post_request("#{base_url}/charges/#{flw_ref}/void", payload) 17 | return response 18 | end 19 | 20 | def refund_preauth(flw_ref, data) 21 | base_url = flutterwave_object.base_url 22 | payload = data.to_json 23 | response = post_request("#{base_url}/charges/#{flw_ref}/refund", payload) 24 | return response 25 | end 26 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/qr.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class QR < Base 5 | def initiate_charge(data) 6 | base_url = flutterwave_object.base_url 7 | # only update the payload with the transaction reference if it isn't already added to the payload 8 | if !data.key?("tx_ref") 9 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 10 | end 11 | # check the currency to determine the type and the required parameters 12 | required_parameters = ["amount", "fullname", "email", "phone_number", "tx_ref", "currency"] 13 | 14 | check_passed_parameters(required_parameters, data) 15 | type = "qr" 16 | payload = data.to_json 17 | 18 | response = post_request("#{base_url}#{BASE_ENDPOINTS::CHARGE_ENDPOINT}?type=#{type}", payload) 19 | return response 20 | end 21 | 22 | # mthod to verify transaction 23 | def verify_charge(id) 24 | base_url = flutterwave_object.base_url 25 | response = get_request("#{base_url}/transactions/#{id}/verify") 26 | return response 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/settlements.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Settlements < Base 5 | 6 | def get_settlements 7 | base_url = flutterwave_object.base_url 8 | response = get_request("#{base_url}/settlements") 9 | return response 10 | end 11 | 12 | def get_settlement(id) 13 | base_url = flutterwave_object.base_url 14 | response = get_request("#{base_url}/settlements/#{id}") 15 | return response 16 | end 17 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/subaccount.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Subaccount < Base 5 | def create_subaccount(data) 6 | base_url = flutterwave_object.base_url 7 | required_parameters = ["account_bank", "account_number", "business_name", "business_contact", "country", "split_value", "business_mobile"] 8 | check_passed_parameters(required_parameters, data) 9 | payload = data.to_json 10 | response = post_request("#{base_url}/subaccounts", payload) 11 | return response 12 | end 13 | 14 | def fetch_subaccounts 15 | base_url = flutterwave_object.base_url 16 | response = get_request("#{base_url}/subaccounts") 17 | return response 18 | end 19 | 20 | def fetch_subaccount(id) 21 | base_url = flutterwave_object.base_url 22 | response = get_request("#{base_url}/subaccounts/#{id}") 23 | return response 24 | end 25 | 26 | def update_subaccount(id, data) 27 | base_url = flutterwave_object.base_url 28 | payload = data.to_json 29 | response = put_request("#{base_url}/subaccounts/#{id}", payload) 30 | return response 31 | end 32 | 33 | def delete_subaccount(id) 34 | base_url = flutterwave_object.base_url 35 | payload = {} 36 | payload = payload.to_json 37 | response = delete_request("#{base_url}/subaccounts/#{id}", payload) 38 | return response 39 | end 40 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/subscriptions.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Subscriptions < Base 5 | 6 | def get_all_subscriptions 7 | base_url = flutterwave_object.base_url 8 | response = get_request("#{base_url}/subscriptions") 9 | return response 10 | end 11 | 12 | def cancel_subscription(id) 13 | base_url = flutterwave_object.base_url 14 | payload = {} 15 | payload = payload.to_json 16 | response = put_request("#{base_url}/subscriptions/#{id}/cancel", payload) 17 | end 18 | 19 | def activate_subscription(id) 20 | base_url = flutterwave_object.base_url 21 | payload = {} 22 | payload = payload.to_json 23 | response = put_request("#{base_url}/subscriptions/#{id}/activate", payload) 24 | end 25 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/tokenized_charge.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class TokenizedCharge < Base 5 | 6 | # method to charge with token 7 | def tokenized_charge(data) 8 | base_url = flutterwave_object.base_url 9 | # only update the payload with the transaction reference if it isn't already added to the payload 10 | if !data.key?("tx_ref") 11 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 12 | end 13 | 14 | required_parameters = [ "token", "currency", "country", "amount", "tx_ref", "email"] 15 | check_passed_parameters(required_parameters, data) 16 | 17 | response = post_request("#{base_url}/tokenized-charges", data.to_json) 18 | 19 | return response 20 | 21 | end 22 | 23 | def verify_tokenized_charge(id) 24 | base_url = flutterwave_object.base_url 25 | response = get_request("#{base_url}/transactions/#{id}/verify") 26 | return response 27 | end 28 | 29 | # method for updating token detials 30 | def update_token(data, token) 31 | base_url = flutterwave_object.base_url 32 | response = put_request("#{base_url}/tokens/#{token}", data.to_json) 33 | return response 34 | end 35 | 36 | # method to create bulk tokenized charges 37 | def bulk_tokenized_charge(data) 38 | base_url = flutterwave_object.base_url 39 | required_parameters = ["title", "retry_strategy", "bulk_data"] 40 | check_passed_parameters(required_parameters, data) 41 | 42 | payload = data.to_json 43 | 44 | response = post_request("#{base_url}/bulk-tokenized-charges/", payload) 45 | return response 46 | end 47 | 48 | #method to get status of a bulk tokenized charges 49 | def bulk_tokenized_charge_status(bulk_id) 50 | base_url = flutterwave_object.base_url 51 | response = get_request("#{base_url}/bulk-tokenized-charges/#{bulk_id}") 52 | return response 53 | end 54 | 55 | #method to get all the bulk tokenized transactions 56 | def bulk_tokenized_charge_transactions(bulk_id) 57 | base_url = flutterwave_object.base_url 58 | response = get_request("#{base_url}/bulk-tokenized-charges/#{bulk_id}/transactions") 59 | return response 60 | end 61 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/transactions.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Transactions < Base 5 | def transaction_fee(currency, amount) 6 | base_url = flutterwave_object.base_url 7 | # required_parameters = ["amount", "currency"] 8 | # check_passed_parameters(required_parameters, data) 9 | response = get_request("#{base_url}/transactions/fee?amount=#{amount}¤cy=#{currency}") 10 | return response 11 | end 12 | 13 | def get_transactions 14 | base_url = flutterwave_object.base_url 15 | response = get_request("#{base_url}/transactions") 16 | return response 17 | 18 | end 19 | 20 | def verify_transaction(id) 21 | base_url = flutterwave_object.base_url 22 | response = get_request("#{base_url}/transactions/#{id}/verify") 23 | return response 24 | end 25 | 26 | def transactions_events(id) 27 | base_url = flutterwave_object.base_url 28 | response = get_request("#{base_url}/transactions/#{id}/events") 29 | return response 30 | end 31 | 32 | def initiate_a_refund(data, id) 33 | base_url = flutterwave_object.base_url 34 | payload = data.to_json 35 | response = post_request("#{base_url}/transactions/#{id}/refund", payload) 36 | return response 37 | end 38 | 39 | #resend transaction webhook 40 | def resend_transaction_webhook(payload) 41 | base_url = flutterwave_object.base_url 42 | response = post_request("#{base_url}/transactions/resend-hook", payload.to_json) 43 | return response 44 | end 45 | 46 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/transfer.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class Transfer < Base 5 | 6 | def transfer_fee(currency,amount) 7 | base_url = flutterwave_object.base_url 8 | response = get_request("#{base_url}/transfers/fee?currency=#{currency}&amount=#{amount}") 9 | return response 10 | end 11 | 12 | def initiate_transfer(data) 13 | base_url = flutterwave_object.base_url 14 | # only update the payload with the transaction reference if it isn't already added to the payload 15 | if !data.key?("tx_ref") 16 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 17 | end 18 | 19 | required_parameters = ["amount", "currency", "account_bank", "account_number"] 20 | check_passed_parameters(required_parameters, data) 21 | payload = data.to_json 22 | response = post_request("#{base_url}/transfers", payload) 23 | return response 24 | end 25 | 26 | def initiate_bulk_transfer(data) 27 | base_url = flutterwave_object.base_url 28 | required_parameters = ["title", "bulk_data"] 29 | check_passed_parameters(required_parameters, data) 30 | payload = data.to_json 31 | response = post_request("#{base_url}/bulk-transfers", payload) 32 | return response 33 | end 34 | 35 | def get_all_transfers 36 | base_url = flutterwave_object.base_url 37 | response = get_request("#{base_url}/transfers") 38 | return response 39 | end 40 | 41 | def get_a_transfer(id) 42 | base_url = flutterwave_object.base_url 43 | response = get_request("#{base_url}/transfers/#{id}") 44 | return response 45 | end 46 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/ussd_payment.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class USSD < Base 5 | def initiate_charge(data) 6 | base_url = flutterwave_object.base_url 7 | # only update the payload with the transaction reference if it isn't already added to the payload 8 | if !data.key?("tx_ref") 9 | data.merge!({"tx_ref" => Util.transaction_reference_generator}) 10 | end 11 | # check the currency to determine the type and the required parameters 12 | required_parameters = ["amount", "account_bank", "email", "phone_number", "tx_ref", "currency"] 13 | 14 | check_passed_parameters(required_parameters, data) 15 | type = "ussd" 16 | payload = data.to_json 17 | response = post_request("#{base_url}#{BASE_ENDPOINTS::CHARGE_ENDPOINT}?type=#{type}", payload) 18 | return response 19 | end 20 | 21 | # mthod to verify transaction 22 | def verify_charge(id) 23 | base_url = flutterwave_object.base_url 24 | response = get_request("#{base_url}/transactions/#{id}/verify") 25 | return response 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/virtual_account_number.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class VirtualAccountNumber < Base 5 | 6 | def create_virtual_account_number(data) 7 | base_url = flutterwave_object.base_url 8 | required_parameters = ["email", "duration", "frequency", "tx_ref"] 9 | check_passed_parameters(required_parameters, data) 10 | payload = data.to_json 11 | response = post_request("#{base_url}/virtual-account-numbers", payload) 12 | return response 13 | end 14 | 15 | def create_bulk_virtual_account_number(data) 16 | base_url = flutterwave_object.base_url 17 | payload = data.to_json 18 | response = post_request("#{base_url}/bulk-virtual-account-numbers", payload) 19 | return response 20 | end 21 | 22 | def get_bulk_virtual_account_number(batch_id) 23 | base_url = flutterwave_object.base_url 24 | response = get_request("#{base_url}/bulk-virtual-account-numbers/#{batch_id}") 25 | return response 26 | end 27 | 28 | def get_virtual_account_number(order_ref) 29 | base_url = flutterwave_object.base_url 30 | response = get_request("#{base_url}/virtual-account-numbers/#{order_ref}") 31 | return response 32 | end 33 | 34 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/flutterwave_objects/virtual_card.rb: -------------------------------------------------------------------------------- 1 | require_relative "base/base.rb" 2 | require 'json' 3 | 4 | class VirtualCard < Base 5 | 6 | def create_virtual_card(data) 7 | base_url = flutterwave_object.base_url 8 | required_parameters = ["currency", "amount", "billing_name"] 9 | check_passed_parameters(required_parameters, data) 10 | payload = data.to_json 11 | response = post_request("#{base_url}/virtual-cards", payload) 12 | return response 13 | end 14 | 15 | def get_all_virtual_cards 16 | base_url = flutterwave_object.base_url 17 | response = get_request("#{base_url}/virtual-cards") 18 | return response 19 | end 20 | 21 | def get_virtual_card(id) 22 | base_url = flutterwave_object.base_url 23 | response = get_request("#{base_url}/virtual-cards/#{id}") 24 | return response 25 | end 26 | 27 | def fund_virtual_card(id, data) 28 | base_url = flutterwave_object.base_url 29 | required_parameters = [ "amount"] 30 | check_passed_parameters(required_parameters, data) 31 | payload = data.to_json 32 | response = post_request("#{base_url}/virtual-cards/#{id}/fund", payload) 33 | return response 34 | end 35 | 36 | def terminate_virtual_card(id) 37 | base_url = flutterwave_object.base_url 38 | payload = {} 39 | payload = payload.to_json 40 | response = put_request("#{base_url}/virtual-cards/#{id}/terminate", payload) 41 | return response 42 | end 43 | 44 | def get_virtual_card_transactions(id, from, to, index, size) 45 | base_url = flutterwave_object.base_url 46 | response = get_request("#{base_url}/virtual-cards/#{id}/transactions", {"from" => from, "to" => to, "index" => index, "size" => size}) 47 | return response 48 | end 49 | 50 | def withdraw_from_virtual_card(id, data) 51 | base_url = flutterwave_object.base_url 52 | required_parameters = [ "amount"] 53 | check_passed_parameters(required_parameters, data) 54 | payload = data.to_json 55 | response = post_request("#{base_url}/virtual-cards/#{id}/withdraw", payload) 56 | return response 57 | end 58 | 59 | def block_unblock_virtual_card(id, status_action) 60 | base_url = flutterwave_object.base_url 61 | payload = {} 62 | payload = payload.to_json 63 | response = put_request("#{base_url}/virtual-cards/#{id}/status/#{status_action}", payload) 64 | return response 65 | end 66 | end -------------------------------------------------------------------------------- /lib/flutterwave_sdk/version.rb: -------------------------------------------------------------------------------- 1 | module FlutterwaveSdk 2 | VERSION = "0.1.1" 3 | end 4 | -------------------------------------------------------------------------------- /spec/flutterwave_card_spec.rb: -------------------------------------------------------------------------------- 1 | require 'dotenv' 2 | require 'spec_helper' 3 | require "flutterwave_sdk/flutterwave_objects/card" 4 | 5 | Dotenv.load 6 | 7 | test_public_key = ENV['TEST_PUBLIC_KEY'] 8 | test_secret_key = ENV['TEST_SECRET_KEY'] 9 | test_encryption_key = ENV['TEST_ENCRYPTION_KEY'] 10 | 11 | 12 | payload = { 13 | "type" => "card", 14 | "card_number" => "4187427415564246", 15 | "cvv" => "828", 16 | "expiry_month" => "09", 17 | "expiry_year" => "32", 18 | "currency" => "NGN", 19 | "amount" => "10", 20 | "email" => "developers@flutterwavego.com", 21 | "fullname" => "Ifunanya ikemma", 22 | "tx_ref" => "MC-" + Date.today.to_s, 23 | "redirect_url" => "https://webhook.site/3ed41e38-2c79-4c79-b455-97398730866c" 24 | } 25 | 26 | pin_payload = { 27 | "type" => "card", 28 | "card_number" => "4187427415564246", 29 | "cvv" => "828", 30 | "expiry_month" => "09", 31 | "expiry_year" => "32", 32 | "currency" => "NGN", 33 | "amount" => "10", 34 | "email" => "developers@flutterwavego.com", 35 | "fullname" => "Ifunanya ikemma", 36 | "tx_ref" => "MC-" + Date.today.to_s, 37 | "redirect_url" => "https://webhook.site/3ed41e38-2c79-4c79-b455-97398730866c", 38 | "authorization": { 39 | "mode": "pin", 40 | "pin": "3310", 41 | } 42 | } 43 | 44 | incomplete_card_payload = { 45 | "type" => "card", 46 | # "card_number" => "5531886652142950", 47 | "cvv" => "564", 48 | "expiry_month" => "09", 49 | "expiry_year" => "32", 50 | "currency" => "NGN", 51 | "amount" => "10", 52 | "email" => "developers@flutterwavego.com", 53 | "fullname" => "Ifunanya ikemma", 54 | "tx_ref" => "MC-" + Date.today.to_s, 55 | "redirect_url" => "https://webhook.site/3ed41e38-2c79-4c79-b455-97398730866c" 56 | } 57 | 58 | RSpec.describe Card do 59 | flutterwave = Flutterwave.new(test_public_key, test_secret_key, test_encryption_key) 60 | card = Card.new(flutterwave) 61 | pin_charge = card.initiate_charge(pin_payload) 62 | 63 | context "when a merchant tries to charge a customers card" do 64 | it "should return a card object" do 65 | expect(card.nil?).to eq(false) 66 | end 67 | 68 | it 'should raise Error if card payload is incomplete' do 69 | begin 70 | incomplete_card_payload_response = card.initiate_charge(incomplete_card_payload) 71 | rescue => e 72 | expect(e.instance_of? IncompleteParameterError).to eq true 73 | end 74 | end 75 | 76 | it 'should check if authentication is required after charging a card' do 77 | first_payload_response = card.initiate_charge(payload) 78 | expect(first_payload_response["meta"]["authorization"]["mode"].nil?).to eq(false) 79 | end 80 | 81 | it 'should successfully charge card with suggested auth PIN' do 82 | second_payload_response = pin_charge 83 | expect(second_payload_response["data"]["status"]).to eq("pending") 84 | end 85 | 86 | it 'should return chargeResponseCode 00 after successfully validating with flwRef and OTP' do 87 | card_validate_response = card.validate_charge(pin_charge["data"]["flw_ref"], "12345") 88 | expect(card_validate_response["data"]["processor_response"]).to eq("successful") 89 | end 90 | 91 | it 'should return chargecode 00 after successfully verifying a card transaction with txRef' do 92 | card_validate_response = card.validate_charge(pin_charge["data"]["flw_ref"], "12345") 93 | card_verify_response = card.verify_charge(card_validate_response["data"]["id"]) 94 | expect(card_verify_response["data"]["processor_response"]).to eq("successful") 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /spec/flutterwave_momo_spec.rb: -------------------------------------------------------------------------------- 1 | require 'dotenv' 2 | require 'spec_helper' 3 | require "flutterwave_sdk/flutterwave_objects/mobile_money" 4 | require "flutterwave_sdk/flutterwave_objects/transactions" 5 | 6 | Dotenv.load 7 | 8 | test_public_key = ENV['TEST_PUBLIC_KEY'] 9 | test_secret_key = ENV['TEST_SECRET_KEY'] 10 | test_encryption_key = ENV['TEST_ENCRYPTION_KEY'] 11 | 12 | payload = { 13 | "tx_ref" => "Sample_RBRef154", 14 | "amount" => "50", 15 | "currency" => "GHS", 16 | "network" => "MTN", 17 | "email" => "developers@flutterwavego.com", 18 | "phone_number" => "054709929220", 19 | "fullname" => "Flutterwave Developers", 20 | "client_ip" => "154.123.220.1", 21 | "device_fingerprint" => "62wd23423rq32dskd4323qew1" 22 | 23 | } 24 | 25 | incomplete_payload = { 26 | "tx_ref" => "Sample_RBRef131", 27 | "amount" => "50", 28 | "currency" => "GHS", 29 | # "email" => "developers@flutterwavego.com", 30 | "phone_number" => "054709929220", 31 | "fullname" => "John Madakin", 32 | "client_ip" => "Flutterwave Developers", 33 | "device_fingerprint" => "62wd23423rq32dskd4323qew1" 34 | 35 | } 36 | 37 | momo_id = 3440004 38 | 39 | 40 | RSpec.describe MobileMoney do 41 | flutterwave = Flutterwave.new(test_public_key, test_secret_key, test_encryption_key) 42 | mobile_money = MobileMoney.new(flutterwave) 43 | transactions = Transactions.new(flutterwave) 44 | mobile_money_charge = mobile_money.initiate_charge(payload) 45 | 46 | 47 | context "when a merchant tries to charge a customers via mobile money" do 48 | it "should return a mobile money object" do 49 | expect(mobile_money.nil?).to eq(false) 50 | end 51 | 52 | it 'should raise Error if the mobile money payload is incomplete' do 53 | begin 54 | incomplete_mobile_money_response = mobile_money.initiate_charge(incomplete_payload) 55 | rescue => e 56 | expect(e.instance_of? IncompleteParameterError).to eq true 57 | end 58 | end 59 | 60 | it 'should successfully generate payment link for the charge' do 61 | payload_response = mobile_money_charge 62 | expect(payload_response["status"]).to eq("success") 63 | end 64 | 65 | it 'should successfully verify mobile money payment' do 66 | verify_response = mobile_money.verify_charge(momo_id) 67 | expect(verify_response["data"]["processor_response"]).to eq("Approved") 68 | end 69 | 70 | it 'should successfully verify fees for mobile money payments' do 71 | currency = "GHS" 72 | amount = "5000" 73 | verify_fee_response = transactions.transaction_fee(currency, amount) 74 | expect(verify_fee_response["data"]["fee"]).to eq(70) 75 | end 76 | 77 | end 78 | end -------------------------------------------------------------------------------- /spec/flutterwave_momo_tzs_spec.rb: -------------------------------------------------------------------------------- 1 | require 'dotenv' 2 | require 'spec_helper' 3 | require "flutterwave_sdk/flutterwave_objects/mobile_money" 4 | require "flutterwave_sdk/flutterwave_objects/transactions" 5 | 6 | Dotenv.load 7 | 8 | test_public_key = ENV['TEST_PUBLIC_KEY'] 9 | test_secret_key = ENV['TEST_SECRET_KEY'] 10 | test_encryption_key = ENV['TEST_ENCRYPTION_KEY'] 11 | 12 | payload = { 13 | "tx_ref" => "MC-" + + Date.today.to_s, 14 | "amount" => "100", 15 | "currency" => "TZS", 16 | "email" => "ifunanyaikemma@gmail.com", 17 | "phone_number" => "0782835136", 18 | "fullname" => "Yolande Aglae Colbert", 19 | "network" => "Halopesa", 20 | } 21 | 22 | incomplete_payload = { 23 | "tx_ref" => "MC-158523sdsdsd", 24 | "amount" => "100", 25 | "currency" => "TZS", 26 | "email" => "ifunanyaikemma@gmail.com", 27 | } 28 | 29 | RSpec.describe MobileMoney do 30 | flutterwave = Flutterwave.new(test_public_key, test_secret_key, test_encryption_key) 31 | mobile_money = MobileMoney.new(flutterwave) 32 | transactions = Transactions.new(flutterwave) 33 | mobile_money_charge = mobile_money.initiate_charge(payload) 34 | 35 | 36 | context "when a merchant tries to charge a customers via mobile money" do 37 | it "should return a mobile money object" do 38 | expect(mobile_money.nil?).to eq(false) 39 | end 40 | 41 | it 'should raise Error if the mobile money payload is incomplete' do 42 | begin 43 | incomplete_mobile_money_response = mobile_money.initiate_charge(incomplete_payload) 44 | rescue => e 45 | expect(e.instance_of? IncompleteParameterError).to eq true 46 | end 47 | end 48 | 49 | it 'should successfully generate payment link for the charge' do 50 | payload_response = mobile_money_charge 51 | expect(payload_response["status"]).to eq("success") 52 | end 53 | 54 | it 'should successfully return processor response ' do 55 | payload_response = mobile_money_charge 56 | expect(payload_response["data"]["processor_response"]).to eq("Transaction in progress") 57 | end 58 | 59 | it 'should successfully return the auth model' do 60 | payload_response = mobile_money_charge 61 | expect(payload_response["data"]["auth_model"]).to eq("MOBILEMONEY") 62 | end 63 | 64 | it 'should successfully verify fees for mobile money payments' do 65 | currency = "TZS" 66 | amount = "100" 67 | verify_fee_response = transactions.transaction_fee(currency, amount) 68 | expect(verify_fee_response["data"]["fee"]).to eq(1.4) 69 | end 70 | 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /spec/flutterwave_sdk_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | test_public_key = ENV['TEST_PUBLIC_KEY'] 4 | test_secret_key = ENV['TEST_SECRET_KEY'] 5 | test_encryption_key = ENV['TEST_ENCRYPTION_KEY'] 6 | 7 | invalid_test_public_key = ENV['INVALID_PUBLIC_TEST'] 8 | invalid_test_secret_key = ENV['INVALID_SECRET_TEST'] 9 | 10 | RSpec.describe Flutterwave do 11 | 12 | flutterwave = Flutterwave.new(test_public_key, test_secret_key, test_encryption_key) 13 | it "should return the valid flutterwave object" do 14 | expect(flutterwave.nil?).to eq(false) 15 | end 16 | 17 | # it "should return valid public key" do 18 | # expect(flutterwave.public_key[0..7]).to eq("FLWPUBK-") || expect(flutterwave.public_key[0..11]).to eq("FLWPUBK_TEST") 19 | # end 20 | 21 | # it "should return valid secret key" do 22 | # expect(flutterwave.secret_key[0..7]).to eq("FLWSECK-") || expect(flutterwave.secret_key[0..11]).to eq("FLWSECK_TEST") 23 | # end 24 | 25 | it "should return valid public key" do 26 | expect(flutterwave.public_key[0..11]).to eq("FLWPUBK_TEST") 27 | end 28 | 29 | it "should return valid secret key" do 30 | expect(flutterwave.secret_key[0..11]).to eq("FLWSECK_TEST") 31 | end 32 | 33 | it 'should raise Error if invalid public key set' do 34 | begin 35 | flutterwave_pub_key_error = Flutterwave.new(invalid_test_public_key, test_secret_key) 36 | rescue => e 37 | expect(e.instance_of? FlutterwaveBadKeyError).to eq true 38 | end 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # require "bundler/setup" 2 | require "flutterwave_sdk" 3 | 4 | RSpec.configure do |config| 5 | # Enable flags like --only-failures and --next-failure 6 | config.example_status_persistence_file_path = ".rspec_status" 7 | 8 | # Disable RSpec exposing methods globally on `Module` and `main` 9 | config.disable_monkey_patching! 10 | 11 | config.expect_with :rspec do |c| 12 | c.syntax = :expect 13 | end 14 | end 15 | --------------------------------------------------------------------------------