Building with and Testing Rapyd's OpenAPI
Tags: flutter, payments, fintech, tutorial
Published: 2024-07-11 08:00:00

The [Rapyd API](https://www.rapyd.net/developers/get-started/) provides a straightforward and efficient process for integrating payment infrastructures into your application. Rapyd also recently introduced an OpenAPI specification designed to further simplify the integration of Rapyd's payment-related functionalities. As such, you are able to seamlessly accept various kinds of payments, streamline cross-border transactions, and enhance your business's cash flow management.

This article explains how to integrate Rapyd's OpenAPI into an existing Flutter application, which has a product page, checkout button, and payment success and failure pages.

## Building an Application with Rapyd's OpenAPI

Before you begin, you'll need the Flutter SDK installed on your local computer. If you don't already have the SDK, go to the [install page](https://docs.flutter.dev/get-started/install), select your operating system, and follow the installation steps provided for your operating system.

You'll also need a Rapyd account, which you can easily create on the [sign-up page](https://dashboard.rapyd.net/sign-up).

### Cloning and Demonstrating the Flutter Demo App

So you can focus on the integration, this article uses an already-existing Flutter app. To clone the app, navigate to the [GitHub repo](https://github.com/Rapyd-Samples/rapyd-openapi-flutter-checkout-demo), click the green **Code** button on the top right, and you should see different clone options.

![GitHub repo](https://i.imgur.com/F7EEi0B.png)

Use any of the options to clone the repo, and then change the directory to the application directory and run the application with the following command, where `{{YOUR_PORT_NUMBER}}` is your preferred and open port number:

```
flutter run -d chrome --web-port `{{YOUR_PORT_NUMBER}}` --web-hostname 0.0.0.0 --web-browser-flag "--disable-web-security"
```

This tutorial uses port 8080. The Flutter demo is built mainly for Flutter web, so irrespective of your machine's operating system, you will be able to demo the application. When you run the command, you should see an output similar to the following:

![Flutter run terminal](https://i.imgur.com/yWKz3Zs.png)

A new Chrome window will open automatically, showing the landing page.

![Application landing page](https://i.imgur.com/v3Q9NJo.png)

Click on any of the products to see the product detail page.

![Application product page](https://i.imgur.com/y3ORpRl.png)

Click the **Checkout** button to see the payment page.

![Application checkout page](https://i.imgur.com/dGq60J6.png)

Fill out the payment form using any details. After filling out the form, click on the **Pay** button. No payment or action occurs when you click the button as you are yet to integrate Rapyd. However, in the case of a successful payment, you would be redirected to the "payment successful" page.

![Application success page](https://i.imgur.com/IjrYqVS.png)

### Integrating Rapyd's OpenAPI into the Demo Flutter Application

The following instructions will guide you through the process of integrating Rapyd's OpenAPI into the application, allowing you to make an actual or test payment to purchase a product.

#### Obtaining Rapyd Credentials

You'll need to locate your access and secret keys as you are going to use them on every API request. To locate these, navigate to the [Rapyd Client Portal login page](https://dashboard.rapyd.net/login), log in with your login details, and click **Developers** on the sidebar. You should be routed to Rapyd's Credential Details page.

![Rapyd's Credential Details](https://i.imgur.com/B7OWKeq.png)

#### Installing the Required Package

The Flutter http, crypto, and convert packages must be installed to consume the Rapyd APIs. To install the packages, go to the root directory of the application and run the following command:

 ```bash 
flutter pub add http && flutter pub add crypto && flutter pub add convert
``` 

Alternatively, you can add the code snippet below into the **pubspec.yaml** file under the `dependencies` key:

```
  http: ^0.13.4
  crypto: ^3.0.3
  convert: ^3.1.1
```

### Setting Up Raypd Request Headers and Base Functions

You'll now set up the request headers and the base functions in a utility file named **rapyd.dart**.

Start by creating a new folder named `utilities` in the `lib` folder. In the `utilities` folder, create a file named **rapyd.dart**.

Into that file, copy and paste the following code snippet, which contains functions that set up the salt, signature, request headers, and a function that receives the API method and API endpoint URL. The request body then initiates an API request to Rapyd:
  
```
import 'dart:convert';
import 'dart:math';
import 'package:convert/convert.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';

class Rapyd {
  // Declaring global variables
  final String ACCESS_KEY = "{{YOUR_ACCESS_KEY}}";
  final String SECRET_KEY = "{{YOUR_ACCESS_KEY}}";
  final String BASEURL = "https://sandboxapi.rapyd.net";

  // Generating the salt for each request
  String getSaltString(int len) {
    var randomValues = List<int>.generate(len, (i) => Random.secure().nextInt(256));
    return base64Url.encode(randomValues);
  }

  // Generating the Signature for each request
  String getSignature(String httpMethod, String urlPath, String salt,
      String timestamp, String dataBody) {
    // string concatenation prior to string hashing
    String sigString = httpMethod +
        urlPath +
        salt +
        timestamp +
        ACCESS_KEY +
        SECRET_KEY +
        dataBody;

    // using the SHA256 method to run the concatenated string through HMAC
    Hmac hmac = Hmac(sha256, utf8.encode(SECRET_KEY));
    Digest digest = hmac.convert(utf8.encode(sigString));
    var ss = hex.encode(digest.bytes);

    // encoding and returning the result
    return base64UrlEncode(ss.codeUnits);
  }

  // Generating the Headers for each request
  Map<String, String> getHeaders(String urlEndpoint, {String body = ""}) {
    //generate a random string of length 16
    String salt = getSaltString(16);

    //calculating the unix timestamp in seconds
    String timestamp = (DateTime.now().toUtc().millisecondsSinceEpoch / 1000)
        .round()
        .toString();

    //generating the signature for the request according to the docs
    String signature =
        getSignature("post", urlEndpoint, salt, timestamp, body);

    //Returning a map containing the headers and generated values
    return <String, String>{
      "access_key": ACCESS_KEY,
      "signature": signature,
      "salt": salt,
      "timestamp": timestamp,
      "Content-Type": "application/json",
    };
  }

  //  helper function to make all HTTP request
  Future<http.StreamedResponse> httpWithMethod(String method, String url, String dataBody, Map<String, String> headers) async {
    var request = http.Request(method, Uri.parse(url))
    ..body = dataBody
    ..headers.addAll(headers);

    // Add any additional body content here.
    return request.send();
  }

  // fuction to make all API request
  Future<Map> makeRequest(String method, String url, Object bodyData) async {

    try {
      final responseURL = "$BASEURL$url";
      final String body = jsonEncode(bodyData);

      var response = await httpWithMethod(method, responseURL, body,  getHeaders(url, body: body));

      var respStr = await response.stream.bytesToString();

      Map repBody = jsonDecode(respStr) as Map;
      //return data if request was successful
      if (response.statusCode == 200) {
        return repBody["data"] as Map;
      }

      throw repBody["status"] as Map;

    } catch (error) {

    throw error;

    }

  }
}
```

Ensure you change `{{YOUR_ACCESS_KEY}}` to your access key and `{{YOUR_SECRET_KEY}}` to your secret key.

Keep in mind that when developing a real-world application, it is advisable to store your API keys using an environment variable.

#### Raypd's OpenAPI Overview and Payment Endpoint Integration

This tutorial consumes only the payment endpoint. To get a full list of the OpenAPI endpoints, go to the [workspace overview](https://www.postman.com/rapyd-dev/workspace/rapyd-dev/collection/22519936-30d06119-8a82-434d-a375-baf5030bd26f) on Postman. Ensure you fork the API collection so you can edit it and run the request on your Postman account. Follow the instructions on the overview page to properly fork the collection alongside Rapyd's OpenAPI environment.

For the payment endpoint, this tutorial uses the "pay with Visa card" type. You can also explore the [official documentation](https://docs.rapyd.net/en/create-payment.html).

To consume the payment endpoint using the "pay with Visa card" type, navigate to the **checkout_view_page.dart** file and import the Rapyd utility file you created in the previous step:

```
import 'utilities/rapyd.dart'; // Import the Rapyd Utilities
```

In the same file, find this code snippet:

```
      print(number);
      print(expMonth);
      print(expYear);
      print(name);
      print(cvv);
      print(email);
      print(product);

      redirectTo('/success');

```

Replace it with the following:

```
      final rapydClient = Rapyd();
      final amount = product.price.toStringAsFixed(2);

      final body = <String, dynamic>{
        "amount": amount,
        "currency": "USD",
        "description": "Payment for ${product.name}",
        "receipt_email": email,
        "payment_method": {
              "type": "il_visa_card",
              "fields": {
                  "number": number,
                  "expiration_month": expMonth,
                  "expiration_year": expYear,
                  "cvv": cvv,
                  "name": name
              }
          }
      };

      try {
          final response = await rapydClient.makeRequest("post", "/v1/payments", body);

          if (response["paid"] == true) {

            redirectTo('/success');

          } else {

            redirectTo('/failed');

          }

          print (response);
        } catch (e) {
          print('ERROR: ${e.toString()}');
        }
```

The code snippet instantiates the `Rapyd` class and calls the `makeRequest` function, which accepts the API endpoint method, the API endpoint URL, and the endpoint payload. In this case, the endpoint method is `Post`, the endpoint URL is `Create Payment Endpoint`, and the endpoint payload is the payment and product data assigned to the `body` variable. 
Once the payment is successful, it sends the customer to the "payment successful" page.

### Flutter Application Demonstration

You've successfully integrated Rapyd's OpenAPI, and you can now test the app. As mentioned, the application is primarily designed for compatibility with Flutter web. This means you can run the app without additional configuration regardless of your local machine's operating system.

If you haven't closed the existing terminal used to demo the Futter application, click the terminal and press the R key to hot restart, which triggers a reload of the application. However, if you have closed the terminal, you can run the command below to start the application, where `{{YOUR_PORT_NUMBER}}` is your preferred and open port number:

```
flutter run -d chrome --web-port "{{YOUR_PORT_NUMBER}}" --web-hostname 0.0.0.0 --web-browser-flag "--disable-web-security"
```

A new Chrome window will automatically open, displaying the landing page. The page should look like the screenshot below:

![Application landing page](https://i.imgur.com/v3Q9NJo.png)

Click any of the products to see the product details and purchase the product.

![Application product page](https://i.imgur.com/y3ORpRl.png)

Click **Checkout** to go to a page with a payment form.

![Application checkout page](https://i.imgur.com/dGq60J6.png)

Fill out the payment form using the Visa test card details below:

* **Card number:** 4111111111111111
* **Expiration month:** 12
* **Expiration year:** 27
* **CVV:** 123
* **Name:** any name
* **Email:** any email

After filling out the form, click the **Pay** button. The payment will be processed, and if it's successful, you'll be redirected to the "payment successful" page.

![Application success page](https://i.imgur.com/IjrYqVS.png)

## Get the Code
You can also play with OpenAPI on Postman and enjoy its limitless capability to build payment-dependent applications. This tutorial’s [complete code](https://github.com/Rapyd-Samples/rapyd-openapi-flutter-checkout-demo) is also available on GitHub