Creating a basic online payment flow with Rave and Vue
Tags: flutterwave, vue, javascript, payments
Published: 2019-10-30 07:19:05

---
title: Creating a basic online payment flow with Rave and Vue
published: true
description: An article that describes how to build payment infrastructure  with Rave and Vue
tags: Flutterwave, Vue, JavaScript, Payments
---

JavaScript frameworks and libraries have enabled developers to create optimal solutions when building web apps. Single and progressive web applications have improved features such as loading time, SEO and accessibility. Lightweight frameworks such as Vue - which is incrementally adoptable and manages state seamlessly, are go-to options for anyone who wants to create a web app without the burden of structuring your application the  "right” way. In this tutorial, we'll build a car rental application which will depict a basic payment process with Vue and [Rave](https://flutterwave.com/ng/online-payments-products/rave/) - a payment gateway used by businesses and freelancers to receive payments online. Let's begin.


 
## Getting started

When we are done building this application, our payment flow should be something like this:


- A user sees a car they want to rent from the list of cars available and clicks the  `Book Now`  button
- The user gets redirected to a payment modal where they make payment (preferably via credit card)
- When payment is made, Rave sends the user a receipt but still verifies the authenticity of the transaction. If the transaction is found to be valid, a unique authentication code is shown to the user, else an error message telling the user to retry the payment is displayed.

To build this application, we'll use the following:


- [Vue CLI](https://cli.vuejs.org/): Vue's command line tool used for scaffolding Vue projects.
- [Vuetify](https://vuetifyjs.com): A material component design framework for Vue.
- [Axios](https://www.npmjs.com/package/axios): A lightweight, promise based HTTP client used for making API calls.
- [MarketCheck](https://www.marketcheck.com/): An API that provides access to a database of new, used and certified vehicles.


Let's begin by installing Vue CLI. Navigate to your terminal and input the following command:

```bash
   
    npm install -g @vue/cli-service-global
    # or
    yarn global add @vue/cli-service-global
    
    #create a new Vue project
    vue create car-sales-app
    
    #navigate into the newly created app
    cd car-sales-app

```

For styling our markup, we'll install Vuetify. In your terminal, navigate to your project's folder and input the following command to install Vuetify:

```bash
   
vue add vuetify
#choose default when prompted

#start a development server on localhost:8080
npm run serve
```

On your browser, navigate to  `localhost:8080`  to view the app:


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/bkh0uamrc2ke7zj3i4g5.png)

Next, we'll install Axios. Navigate to your project's folder and input the following command:

```bash
   
    npm install axios

```

After installing Axios, we need to obtain an API key from MarketCheck. To do this, head on to MarketCheck and create an account:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/vqlia97gmslq2wlnfy0f.png)

At this point, the  `main.js`  file, located in the root folder of our project should look like this:


```javascript
   
    import Vue from "vue";
    import App from "./App.vue";
    import vuetify from "./plugins/vuetify";
    Vue.config.productionTip = false;
    new Vue({
      vuetify,
      render: h => h(App)
    }).$mount("#app");

```



## Fetching data from our API

By default, our project has a  `HelloWorld`  component.  Let's delete that component and modify our  `App`  component to make requests to MarketCheck's API using Axios. Using Vue's  `mounted()`  lifecycle method, Axios makes a  `GET`  request to the API:

```javascript
   
// App.vue
<script>
  export default {
    name: "app",
    mounted() {
      axios
        .get('https://marketcheck-prod.apigee.net/v1/search?&year=2016&make=toyota&api_key=INSERT-YOUR-API-KEY-HERE&Content-Type=application/json')
        .then(response => {
            this.carResponse = response.data.listings;
        })
        .catch(error => {
            console.log(error);
        });
    }
  }
</script>
```


`carResponse`  is a data property which is responsible for handling the data received from our API and displaying it on our browser. Let's use UI components from Vuetify and Vue directives to structure our  App component:

```javascript
   
    // App.vue
    <template>
      <div id="app">
        <header>
          <h2>
            RENT A CAR. CALL 080-RENT-A-CAR
          </h2>
        </header>
        <v-container grid-list-xl>
          <v-layout wrap>
            <v-flex xs4 v-for="car in carResponse" :key="car[0]" mb-2>
              <v-card>
                <v-img :src="car.media.photo_links[0]" aspect-ratio="2"></v-img>
                <v-card-title primary-title>
                  <div>
                    <h3>{{ car.build.make }} {{ car.build.model }}</h3>
                    <div>Year: {{ car.build.year }}</div>
                    <div>Type: {{ car.build.vehicle_type }}</div>
                    <div>Mileage: {{ car.miles }} miles</div>
                    <div>NGN {{ car.price }} / Day</div>
                  </div>
                </v-card-title>
                <v-card-actions class="justify-center">
                </v-card-actions>
              </v-card>
            </v-flex>
          </v-layout>
        </v-container>
      </div>
    </template>
    <script>
    import axios from "axios";
    export default {
      name: "app",
      data() {
        return {
          carResponse: [],
          }    
      },
      mounted() {
        axios
          .get('https://marketcheck-prod.apigee.net/v1/search?&year=2016&make=toyota&api_key=INSERT-YOUR-API-KEY-HERE&Content-Type=application/json')
          .then(response => {
            this.carResponse = response.data.listings;
          })
          .catch(error => {
            console.log(error);
          });
      }
    };
    </script>
    <style>
    #app {
      font-family: "Avenir", Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: justify;
      background-color: hsla(0, 0%, 75%, 0.1);
    }
    header {
      margin-bottom: 60px;
      text-align: center;
    }
    </style>

```

Here's a view of the current state of the app in our browser:

{% youtube 2IDtM-QTXsI %}


## Implementing payments with Rave

For now, we are unable to receive payments for any of the displayed vehicles. Let's change that by implementing Rave's payment gateway in our app. First, we need to [sign up](https://rave.flutterwave.com/signup) with Rave and create a merchant account which enables us to receive payment for goods and services:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/rsa7i8mvclugqppa8me5.png)

Once we are through with the sign-up process, we should see a dashboard similar to this:

{% youtube Du7VpFCN21M %}

On the dashboard navigate to  `Settings`  and then the   `API`  tab to retrieve the API keys. As this is a tutorial, switch to   `Test mode`  on the dashboard and make payment using a test card supplied by Rave to avoid disclosing sensitive information either by displaying our real API keys or credit card numbers. Below is a screenshot of your test API keys:


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/3c8ahp7te1uzq78nfffo.png)

 In the  `src/components`  folder, let's create a new component and name it  `RaveModal`.  Using Vue's   `create()`  hook, In our newly created component, we'll create an instance of Rave's inline script and append it to the DOM:

```javascript
   
    // src/components/RaveModal.vue
    created() {
        const script = document.createElement("script");
        script.src = !this.isProduction
          ? "https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/flwpbf-inline.js"
          : "https://api.ravepay.co/flwv3-pug/getpaidx/api/flwpbf-inline.js";
        document.getElementsByTagName("head")[0].appendChild(script);
      }

```

Using Vue's  method  property, we'll embed a payment modal in our component via Rave's  [`getPaidSetup`](https://developer.flutterwave.com/docs/rave-inline-1)  function:

```javascript
   
    // src/components/RaveModal.vue
     methods: {
        payWithRave() {
          window.getpaidSetup({
            customer_email: this.email,
            amount: this.amount,
            txref: this.reference,
            PBFPubKey: this.raveKey,
            onclose: () => this.close(),
            callback: response => this.callback(response),
            currency: this.currency,
            country: this.country,
            custom_title: this.custom_title,
            custom_logo: this.custom_logo,
            payment_method: this.payment_method,
          });
        }
      }

```

Our next step will be to specify what each value in  `getPaidSetup`  should be. We'll do this by using Vue prop types:

```javascript
   
    // src/components/RaveModal.vue 
    props: {
        isProduction: {
          type: Boolean,
          required: false,
          default: false //set to true if you are going live
        },
        email: {
          type: String,
          required: true
        },
        amount: {
          type: Number,
          required: true
        },
        raveKey: {
          type: String,
          required: true
        },
        callback: {
          type: Function,
          required: true,
          default: response => {}
        },
        close: {
          type: Function,
          required: true,
          default: () => {}
        },
        currency: {
          type: String,
          default: "NGN"
        },
        country: {
          type: String,
          default: "NG"
        },
        custom_title: {
          type: String,
          default: ""
        },
        custom_logo: {
          type: String,
          default: ""
        },
        payment_method: {
          type: String,
          default: ""
        }
      }

```

The  `template`  in our  `RaveModal` component won't hold much, just a button that activates the payment modal when clicked:

```javascript
   
 // src/components/RaveModal.vue

<template>
  <div class="rave">
    <button class="button" @click="payWithRave">Book Now</button>
  </div>
</template>
```

Finally, we'll import  `RaveModal`  into our `App`  component and specify all the values of `paywithRave()` :


```javascript
   
    // src/App.vue
    
    <script>
    import Rave from "./components/RaveModal.vue";
    export default {
      name: "app",
      components: {
        Rave
      },
     data() {
        return {
          carResponse: [],
          isProduction: false,
          raveKey: raveKey,
          email: "ugwuraphael@gmail.com",
          amount: "",
          currency: "NGN",
          country: "NG",
          custom: {
            title: "Car Shop",
            logo: carLogo
          },
          paymentMethod: ""
        };
      }
    }
    </script>

```

To include the payment button on our app, embed it in our template:

```javascript
   
// src/App.vue

<template>
  <v-card-actions class="justify-center">
              <rave
                :isProduction="isProduction"
                :email="email"
                :amount="car.price"
                :reference="reference"
                :rave-key="raveKey"
                :callback="callback"
                :close="close"
                :currency="currency"
                :country="country"
                :custom_title="custom.title"
                :custom_logo="custom.logo"
                :payment_method="paymentMethod"
              />
            </v-card-actions>
</template
```

Finally, let's protect our API keys by storing them in a  `.env`  file. In the root folder of your project, create a  `.env`  file and store both MarketCheck and Rave APIs:

```bash
   
    // .env
    
    VUE_APP_CAR_API_KEY='YOUR MARKETCHECK API HERE'
    VUE_APP_RAVE_TEST_KEY='YOUR RAVE API KEY HERE'

```


When you are done, save the  `.env`  file and refer to the stored values in  `App`  like this:

```javascript
   
// src/App.vue
<script>
  const carKey = process.env.VUE_APP_CAR_API_KEY;
  const raveKey = process.env.VUE_APP_RAVE_TEST_KEY;
</script>
```

Restart the development server on your terminal, navigate to your browser and try to make a payment for one of the vehicles:

{% youtube 3vp-5vDKkiQ %}

Upon payment, Rave emails the customer a receipt:

{% youtube u-z199P9_CY %}


## Handling payment authentication


Although we can confirm that a customer made payment by checking our Rave dashboard for details of the transaction, it's still important to perform an authentication check for each transaction to detect issues such as reversed or fraudulent transactions. To achieve this, we'll define the  `callback`  property in Rave's  `getPaidSetup`  function to check for the authenticity of every transaction and return its transaction ID to the customer:

```javascript
   
    <script>
      import Rave from "./components/RaveModal.vue";
      export default {
        name: "app",
        components: {
            Rave
        }
        methods: {
            callback: function(response) {
                if (
                    response.data.tx.status == "successful" &&
                    response.data.tx.chargeResponseCode === "00"
                ) {
                    if (response.data.tx.fraud_status === "ok") {
                        alert(
                            `Authenticate your payment via our mobile app with this code: ${response.data.tx.txRef}`
                        );
                    }
                } else {
                    alert("Your payment could not be processed. Please try again later");
                }
            }
        } 
    </script>

```

Now a customer can pay for an item and get an identifier such as an authentication code as an additional layer of authenticity:

{% youtube cP6XTgRdVTw %}

## Summary

Optimizing performance when building web apps is only going to get more important. Javascript developers have a lot of frameworks and tools to choose from and Vue is an awesome option.  As for implementing payment options seamlessly, Rave gets the job done. To check out the source code of this application, head on to [GitHub](https://github.com/fullstackmafia/car-sales-app).