How to Set Up a Swift Payout with Rapyd Disburse API
Tags: programming, node, payout
Published: 2023-09-12 19:54:40

Swift—the Society for Worldwide Interbank Financial Telecommunications—is a widely popular network used for international money transfers between financial institutions, mainly banks, allowing businesses to easily pay their customers and employees in different countries. Swift’s wire transfer method is the preferred payment method of many businesses worldwide due to its broad availability, cost-effectiveness, security, and reliability.

By pairing Swift with the Rapyd Disburse API, your business can make fast and cost-effective international transactions, ensuring that your customers, business partners, and employees receive their payments in their local currency, on time. Rapyd Disburse is one of Rapyd’s many tools that allow businesses to issue international payments. 

By the end of this tutorial, you will be able to use Rapyd’s sandbox environment to get API keys, perform and authorize API requests, create a Node.js app that uses the Rapyd Disburse API to easily send Swift payments to your customers and employees, and use Rapyd webhooks to listen to and confirm payout transactions upon completion.

## Implementing Swift Payments

In the following sections, you will learn how to use the Rapyd Disburse API to issue international Swift payments by completing the following actions:

- Getting API Keys
- Setting up your application and the Node.js server
- Setting environment variables
- Creating a utilities helper
- Creating routes
- Creating a server instance
- Creating a payment interface page
- Creating event handlers
- Creating the controller
- Running and testing the application 
- Creating a webhook to receive payment confirmation

In order to follow this tutorial and send Swift payouts using the Rapyd Disburse API, you’ll need a Rapyd account. If you haven’t created one yet, you can [sign up here](https://dashboard.rapyd.net/sign-up).

You can find the full code for this project in [this GitHub repository](https://github.com/Rapyd-Samples/rapyd-disburse-swift-payouts).

### Getting the API Keys

Log in to your [Rapyd account](https://dashboard.rapyd.net/login) and activate the sandbox button at the top right corner of your account dashboard. Then, click the **Developer** menu item in the left side menu to get your sandbox credentials. You can use these credentials during the development and testing phases.

![Rapyd developer dashboard API keys](https://i.imgur.com/rO60Q4k.png)

### Setting Up Your Application

In this tutorial, you will be using Express to create a Node.js server. As a starting point, create a new directory, navigate to it in your terminal window, and run the following command to create a `package.json` file, which will store the dependencies for your project:

```
npm init -y
```

Then run the following command to install Express and the other dependencies needed for the project:

```
npm install express dotenv body-parser ejs
```

You'll also be using nodemon to make the development process easier. Run the following command to install it:

```
npm install -g nodemon
```

To keep your code organized with regard to the structure of this application, create these five directories inside your project’s main directory (e.g. mkdir controllers, etc.):

- `controllers`
- `helpers`
- `public`
- `routes`
- `views`

### Setting Environment Variables

This file holds the environment variables that your application will use to authorize API requests. The three variables that you will use for this project are API key, secret key, and wallet ID. 

Create the `.env` file in the main directory and paste in the following code:

```
NODE_ENV=development

ACCESS_KEY=YOUR_ACCESS_KEY
SECRET_KEY=YOUR_SECRET_KEY
PAYOUT_WALLET_ID=YOUR_WALLET_ID_HERE
```

Add your API and secret keys, found on the [developers page](https://docs.rapyd.net/en/developers.html) as the first two variables and leave the wallet ID empty for now. You will get this value later in this tutorial.

### Creating a Utilities Helper

In the `/helpers` directory, create the `utilities.js` file and paste in the following code:

```javascript
/*
* Environment Variables
*/
const https = require('https');
const crypto = require('crypto');
const dotEnv = require('dotenv');
const log = false;

dotEnv.config();

const secretKey = process.env.SECRET_KEY; // Your API Access key
const accessKey = process.env.ACCESS_KEY; // You API secret key

/*
* Make a Request to Rapyd API
*/
async function makeRequest(method, urlPath, body = null) {
  try {
    // API Request parameters
    httpMethod = method;
    httpBaseURL = "sandboxapi.rapyd.net";
    httpURLPath = urlPath; // The request path
    salt = generateRandomString(8); // Randomly created for each request
    idempotency = new Date().getTime().toString(); // Used for payment creation requests
    timestamp = Math.round(new Date().getTime() / 1000); 
    signature = generateSignature(httpMethod, httpURLPath, salt, timestamp, body) // Request Signature
    const options = {
      hostname: httpBaseURL,
      port: 443,
      path: httpURLPath,
      method: httpMethod,
      headers: {
        'Content-Type': 'application/json',
        salt: salt,
        timestamp: timestamp,
        signature: signature,
        access_key: accessKey,
        idempotency: idempotency
      }
    }

    return await httpRequest(options, body, log);
  }
  catch (error) {
    console.error("Error generating request options");
    throw error;
  }
}

/*
* Generate Request Signature
*/
function generateSignature(method, urlPath, salt, timestamp, body) {

  try {
    let bodyString = "";
    if (body) {
      bodyString = JSON.stringify(body);
      bodyString = bodyString == "{}" ? "" : bodyString;
    }

    let toSign = method.toLowerCase() + urlPath + salt + timestamp + accessKey + secretKey + bodyString;
    log && console.log(`toSign: ${toSign}`);

    let hash = crypto.createHmac('sha256', secretKey);
    hash.update(toSign);
    const signature = Buffer.from(hash.digest("hex")).toString("base64")
    log && console.log(`signature: ${signature}`);

    return signature;
  }
  catch (error) {
    console.error("Error generating signature");
    throw error;
  }
}

/*
* Generate a Random Salt String
*/
function generateRandomString(size) {
  try {
    return crypto.randomBytes(size).toString('hex');
  }
  catch (error) {
    console.error("Error generating salt");
    throw error;
  }
}

/*
* Create an HTTP Request
*/
async function httpRequest(options, body) {

  return new Promise((resolve, reject) => {

    try {

      let bodyString = "";
      if (body) {
        bodyString = JSON.stringify(body);
        bodyString = bodyString == "{}" ? "" : bodyString;
      }

      log && console.log(`httpRequest options: ${JSON.stringify(options)}`);
      const req = https.request(options, (res) => {
        let response = {
          statusCode: res.statusCode,
          headers: res.headers,
          body: ''
        };

        res.on('data', (data) => {
          response.body += data;
        });

        res.on('end', () => {

          response.body = response.body ? JSON.parse(response.body) : {}
          log && console.log(`httpRequest response: ${JSON.stringify(response)}`);

          if (response.statusCode !== 200) {
            return reject(response);
          }

          return resolve(response);
        });
      })

      req.on('error', (error) => {
        return reject(error);
      })

      req.write(bodyString)
      req.end();
    }
    catch(err) {
      return reject(err);
    }
  })

}


exports.makeRequest = makeRequest;

```

The functions in this file handle authorizing and sending requests to the Rapyd API servers. You will use these functions later to perform API calls. The `utilities.js` file includes the following four functions:

- `makeRequest`: Includes the logic to communicate with the Rapyd sandbox server
- `generateSignature`: Generates a Rapyd API request signature
- `generateRandomString`: Generates a salt string for the HTTP request
- `httpRequest`: Creates an HTTP request and returns the response

### Creating Routes

Create a file named `index.js` in the `/routes` directory and paste in the following code:

```javascript
const express = require('express');
const path = require('path');
const router = express.Router();
const bodyParser = require('body-parser');
const payoutController = require('../controllers/payoutController')

const app = express();

// Set Render Engine
app.use('/public', express.static('public'));
app.set('view engine', 'ejs');

// Load Body parser for JSON responses
router.use(bodyParser.urlencoded({extended: true}));
router.use(bodyParser.json());

// GET: Home Route
router.get('/', async (req, res) => {
    res.render('../views/payCustomer');
});

// POST: Required Fields
router.post('/get-required-fields', async (req, res, next) => {
    payoutController.getRequiredFields(req, res, next);
});

// POST: Send payout
router.post('/send-payment', async (req, res, next) => {
    payoutController.sendPayment(req, res, next);
});

// POST: Payment Completed Webhook URL
router.post("/payment-complete", (req, res) => {
  console.log(req.body);
  res.status(200).end(); 
});

module.exports = router;

```

In this `/routes/index.js` file, the `ejs` module is set as the rendering engine to render HTML and the `BodyParser` module is configured to handle JSON responses.

Then, the file includes 4 routes:

- `GET /`: The homepage
- `GET /get-required-fields`: The endpoint to get the required fields for the Swift payment method
- `POST /send-payment`: The endpoint to send a Swift payment
- `POST /payment-complete`: The webhook URL to handle the payment complete action

### Creating a Server Instance

Create an `index.js` file in the main project directory and paste in this code:

```javascript
const express = require('express');
const path = require('path');
const router = require('./routes/index');


const app = express();

app.use('/public', express.static('public'));
app.set('view engine', 'ejs');

app.use('/', router);
app.listen(3000);
```

This is the file where you create the server instance. The imported modules are `path`, to set the public resources folder, and `router`, so the server can use the routes that you have previously set in the `/routes/index.js` file.

### Creating a Payment Interface Page

Now, create an `payCustomer.ejs` file in the `/views` folder. Notice that the file extension is `.ejs` because you are using the `ejs` module as the rendering engine. Then, paste this HTML code to this file:

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>SWIFT Payout using Rapyd Disburse</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
  <link rel="stylesheet" href="public/app.css">
</head>
<body>
  <div class="row">
    <div class="col-md-3">
    </div>
    <div class="col-md-6 bg-light">
      <form id="checkoutForm">
        <h1> Rapyd Disburse Swift Payment</h1>
        
        <!-- Initial form fields to get the required fields for the Swift payment method by country -->
        <fieldset>
          
          <p>
            <label for="payout_currency" class="form-label">Customer's Currency</label>
            <input type="text" required id="payout_currency" name="payout_currency" class="form-control" placeholder="Payout Currency" required>
          </p>
          
          <p>
            <label for="user_country">Country</label>
            <input type="text" required id="user_country" name="user_country" class="form-control" placeholder="Country Code, ex: FR" required>
          </p>

          <p>
            <label for="transaction_amount">Amount</label>
            <input type="text" required id="transaction_amount" name="transaction_amount" class="form-control" placeholder="Amount" required>
          </p>
          
        </fieldset>

        <!-- The Button to execute the "getRequiredFields" request -->
        <p>
          <button type="button" id="pay-button" class="btn btn-primary form-control">Pay Salary</button>
        </p>

        <fieldset id="payment-required-fields">
          <!-- Payment fields will show up here -->
        </fieldset>

        <!-- Send Payment Button -->
        <p>
          <button type="submit" id="send-payment-button" class="btn form-control btn-success">Send Payment</button>
        </p>

        <!-- Loading Notification -->
        <div class="alert alert-success request-status-bar" id="request-status-success" role="alert">
          Payment Sent
        </div>
        <!-- Success Notification -->
        <div class="alert alert-warning request-status-bar" id="request-status-loading" role="alert">
          Processing...
        </div>
        <!-- Error Notification -->
        <div class="alert alert-danger request-status-bar" id="request-status-error" role="alert">

        </div>

      </form>
    </div>
    <div class="col-md-3">
    </div>
  </div>

</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="public/app.js"></script>
</html>

```

The HTML code includes the following:

- The fields needed to get the Swift payment’s required fields, which are payout currency, country code, and transaction amount.
- A button to get the required fields and a hidden button to send the payment. 
- Three notification `<div>` tags: one for payment success, one for loading, and one for errors. 
- Four imported resources: Bootstrap CSS for styling and jQuery for JavaScript, as well as `app.css` and `app.js` files.

To add some style to the interface page, create a file named `app.css` in the `public` directory and paste this CSS code:

```css
label {
	text-transform: capitalize;
}

#send-payment-button{
	display: none;
}

.request-status-bar {
	text-align: center;
	display: none;
}
```

### Creating Event Handlers

To handle the form submissions using AJAX, create the `app.js` file in your `/public` directory and paste this code:

```javascript

$(function(){ 

// Pay Salary button Event Listener
  $("#pay-button").click(function(event){
    event.preventDefault();
    $("#request-status-loading").slideDown();

  // AJAX Call
    $.ajax({
      type: 'POST',
      url: '/get-required-fields',
      data: {
        'sender_currency': 'USD',
        'sender_country': 'US',
        'beneficiary_country': $("#user_country").val(),
        'payout_currency': $("#payout_currency").val(),
        'sender_entity_type': 'company',
        'beneficiary_entity_type': 'individual',
        'payout_amount': $("#transaction_amount").val()
      }, 
      success: function (data, status, xhr) {

        //Create Beneficiary Fields
        $("#payment-required-fields").append("<h2>Beneficiary Information</h2>");
        $.each(data.beneficiary_required_fields, function(propName, propVal) {
          var fieldName = propVal.name;
          var isRequired = propVal.is_required == true? "required" : "" ;
          var fieldDesc = propVal.description? propVal.description : "";
          $("#payment-required-fields").append("<label for='"+fieldName+"' class='form-label'>"+fieldName.replace("_", " ")+"</label>");
          if(propVal.is_required == true) $("#payment-required-fields").append("*");
          $("#payment-required-fields").append("<input type='text' id='beneficiary_"+fieldName+"' name='beneficiary_"+fieldName+"' class='form-control' placeholder='"+fieldDesc+"' "+isRequired+">");
        });

        //Create Sender Fields
        $("#payment-required-fields").append("<h2>Sender Information</h2>");
        $.each(data.sender_required_fields, function(propName, propVal) {
          var fieldName = propVal.name;
          var isRequired = propVal.is_required == true? "required" : "" ;
          var fieldDesc = propVal.description? propVal.description : "";
          $("#payment-required-fields").append("<label for='"+fieldName+"' class='form-label'>"+fieldName.replace("_", " ")+"</label>");
          if(propVal.is_required == true) $("#payment-required-fields").append("*");
          $("#payment-required-fields").append("<input type='text' id='sender_"+fieldName+"' name='sender_"+fieldName+"' class='form-control' placeholder='"+fieldDesc+"' "+isRequired+">");
        });

        //Create Transaction Fields
        $("#payment-required-fields").append("<h2>Transaction Details</h2>");
        $.each(data.payout_options, function(propName, propVal) {
          var fieldName = propVal.name;
          var isRequired = propVal.is_required == true? "required" : "" ;
          var fieldDesc = propVal.description? propVal.description : "";
          $("#payment-required-fields").append("<label for='"+fieldName+"' class='form-label'>"+fieldName.replace("_", " ")+"</label>");
          if(propVal.is_required == true) $("#payment-required-fields").append("*");
          $("#payment-required-fields").append("<input type='text' id='transaction_"+fieldName+"' name='transaction_"+fieldName+"' class='form-control' placeholder='"+fieldDesc+"' "+isRequired+">");
        });


        // Show Status
        $("#request-status-error").slideUp();
        $("#request-status-loading").slideUp();
        $("#pay-button").slideUp();
        $("#send-payment-button").slideDown();
      },
      error: function (jqXhr, textStatus, errorMessage) {
        // Show Error
        $("#request-status-loading").slideUp();
        $("#request-status-error").slideDown();
        $("#request-status-error").html(errorMessage);
        console.log('Error' + errorMessage);
      }
    });

  });


// Send button Event Listener
  $("#send-payment-button").click(function(event){
    event.preventDefault();

    $("#request-status-error").slideUp();
    $("#request-status-loading").slideDown();

    // AJAX Call
    $.ajax({
      type: 'POST',
      url: '/send-payment',
      data: {
        'payout_currency': $("#payout_currency").val(),
        'sender_country': 'US',
        'sender_address': $("#sender_address").val(),
        'beneficiary_country': $("#beneficiary_country").val(),
        'sender_entity_type': 'company',
        'beneficiary_address': $("#beneficiary_address").val(),
        'payout_amount': $("#transaction_amount").val(),
        'beneficiary_address': $("#beneficiary_address").val(),
        'beneficiary_city': $("#beneficiary_city").val(),
        'beneficiary_country': $("#beneficiary_country").val(),
        'beneficiary_first_name': $("#beneficiary_first_name").val(),
        'beneficiary_last_name': $("#beneficiary_last_name").val(),
        'beneficiary_state': $("#beneficiary_state").val(),
        'beneficiary_postcode': $("#beneficiary_postcode").val(),
        'beneficiary_account_number': $("#beneficiary_account_number").val(),
        'beneficiary_bic_swift': $("#beneficiary_bic_swift").val(),
        'transaction_description': $("#transaction_description").val(),
        'transaction_statement_descriptor': $("#transaction_statement_descriptor").val()
      }, 
      success: function (data, status, xhr) {
        // Show Status
        $("#request-status-error").slideUp();
        $("#request-status-loading").slideUp();
        // Show Success Status with the Payout ID
        $("#request-status-success").append("<br>"+"Payout ID:"+data.id);
        $("#request-status-success").slideDown();

      },
      error: function (jqXhr, textStatus, errorMessage) {
        // Show Error
        $("#request-status-loading").slideUp();
        $("#request-status-error").slideDown();
        console.log('Error' + errorMessage);
      }

    });

  });
});

```

The file includes two event listeners:

- **“Pay Salary” button click listener:** Shows a loading status, then makes a POST request to the endpoint `/get-required-fields` to send the data entered in the form. After the request execution, it creates the form fields for the Swift payment method in three sections: beneficiary information, sender information, and transaction details.
- **“Send Payment” button click listener:** Shows a loading status, then makes a POST request to the endpoint `/send-payment` to send the data entered in the form that will be used as the API request message body. Once the request is executed, it shows a success message with the payout ID, which is retrieved from the JSON response.

### Creating the Controller

This controller contains the methods that will handle the Rapyd Disburse API requests. Create a file named `payoutController.js` in the `/controllers` directory and paste in the following code:

```javascript
const {makeRequest} = require('../helpers/utilities');
const dotEnv = require('dotenv');

dotEnv.config();

class payoutController{
    
    constructor(){

    }

    // Get Swift payment method required fields using Rapyd Disburse API
    static async getRequiredFields(request, response, next){
        try {
            const { 
              sender_country, 
              sender_currency, 
              beneficiary_country, 
              payout_currency, 
              sender_entity_type, 
              beneficiary_entity_type, 
              payout_amount,
            } = request.body;


            const result = await makeRequest('GET', '/v1/payouts/xx_swift_bank/details?sender_country='+sender_country+'&sender_currency='+sender_currency+'&beneficiary_country='+beneficiary_country+'&payout_currency='+payout_currency+'&sender_entity_type='+sender_entity_type+'&beneficiary_entity_type='+beneficiary_entity_type+'&payout_amount='+payout_amount);
            response.json(result.body.data);
            
          } catch (error) {
            
            response.json(error);
          }
    }

    // Create Swift payment using Rapyd Disburse API
    static async sendPayment(request, response){
        const walletID = process.env.PAYOUT_WALLET_ID; // Wallet ID

        try {
            const requestBody = {
                "ewallet": walletID,
                "merchant_reference_id": "Test-Cash-8888",
                "payout_amount": request.body.payout_amount,
                "payout_method_type": "xx_swift_bank",
                "sender_currency": "USD",
                "sender_country": request.body.sender_country,
                "beneficiary_country": request.body.beneficiary_country,
                "payout_currency": request.body.payout_currency,
                "sender_entity_type": "company",
                "beneficiary_entity_type": "individual",
                "beneficiary": {
                   "payment_type": "regular",
                   "address": request.body.beneficiary_address,
                   "city": request.body.beneficiary_city,
                   "country": request.body.beneficiary_country,
                   "first_name": request.body.beneficiary_first_name,
                   "last_name": request.body.beneficiary_last_name,
                   "state": request.body.beneficiary_state,
                   "postcode": request.body.beneficiary_postcode,
                   "bic_swift": "573675777",
                   "account_number": request.body.beneficiary_account_number,
               },
               "sender": {
                   "company_name" : "My Company",
                   "address": request.body.sender_address,
                   "city": "Anytown",
                   "state": "NY",
                   "phone_number": "+145434653466"
               },
               "description": request.body.transaction_description,
               "statement_descriptor": request.body.transaction_statement_descriptor,
               "metadata": {
                   "merchant_defined": true
               }
           };

            const result = await makeRequest('POST', '/v1/payouts', requestBody);
            console.log("--------------------------");
            console.log(JSON.stringify(result.body.data));
            response.json(result.body.data);
            
          } catch (error) {
            
            response.json(error);
          }
        }

} 

module.exports = payoutController;

```

The controller has two static asynchronous methods:

- `getRequiredFields`: Makes a GET request to the Rapyd Disburse API to retrieve the required fields for a Swift payment and returns a JSON response.
- `sendPayment`: Makes a POST request to create a Swift payout using the data fetched from the HTML form and the wallet ID fetched from the environment variables in the `.env` file.

### Running and Testing the Application

At this point, you are ready to run your application and test sending a Swift payout. In order to send a Swift payout, you need to create a Rapyd wallet and have sufficient funds in it. You can perform these two actions in the Rapyd sandbox environment.

#### Create and Fund a Rapyd Wallet

You can perform this action using [Postman](https://bit.ly/3vxY1aG), and follow the steps to [create and fund a wallet](https://community.rapyd.net/t/create-and-fund-a-wallet/) with the following request URI:

```
POST https://sandboxapi.rapyd.net/v1/user
```

Use this object as the request body:

```json
{
    "first_name": "My Company",
    "ewallet_reference_id": "Test-8888",
    "metadata": {
        "merchant_defined": true
    },
    "type": "company",
    "contact": {
        "phone_number": "+14155588799",
        "email": "sanboxtest@rapyd.net",
        "first_name": "John",
        "last_name": "Doe",
        "contact_type": "business",
        "address": {
            "name": "My Company",
            "line_1": "888 Some Street",
            "city": "Anytown",
            "state": "NY",
            "country": "US",
            "zip": "12345",
            "phone_number": "+14155588799"
        },
        "identification_type": "PA",
        "identification_number": "1234567890",
        "date_of_birth": "11/22/2000",
        "country": "US",
        "nationality": "US",
        "metadata": {
            "merchant_defined": true
        },
        "business_details": {
            "entity_type": "company",
            "name": "My Company",
            "registration_number": "4234567779",
            "industry_category": "company",
            "industry_sub_category": "home services",
            "address": {
                "name": "My Company",
                "line_1": "888 Some Street",
                "line_2": "Suite 1200",
                "city": "Anytown",
                "state": "NY",
                "country": "US",
                "nationality": "IT",
                "zip": "10101",
                "phone_number": "+14155588799",
                "metadata": {
                    "merchant_defined": true
                }
            }
        }
    }
}

```

The Rapyd wallet ID in the JSON response will look something like this: “ewallet_9b63887ff57f1f8cd906c76d74253979”. Copy the wallet ID from the JSON response and paste it into the `.env` file.

To deposit funds in your payout sender currency (USD in this case), use the following as the request URI:

```
POST https://sandboxapi.rapyd.net/v1/account/deposit/
```

And this JSON object as the message body:

```json
{
  "ewallet": "{YOUR-WALLET-ID-FROM-THE-PREVIOUS-RESPONSE}",  
  "amount": "20000", 
  "currency": "USD",    
  "metadata": {    "merchant_defined": true   }
}
```

Once you receive a successful response, you are then ready to run and test the application.

#### Run the Server

Navigate to your project’s main folder in the terminal and run the following command:

```
nodemon index.js
``` 

Go to your browser and open `http://localhost:3000/`. The homepage should look like this:

![Rapyd Disburse Swift payout app homepage](https://i.imgur.com/63NidoG.png)

For this example, you'll be paying out 400 Euros to someone in France, so use "EUR" as the currency code, "FR" as the country code, and "400" as the payout amount. Then, click the **Pay Salary** button.

Once the request is completed, the required fields based on the data you entered will appear as shown in the following image:

![Rapyd Disburse Swift payout required fields](https://i.imgur.com/rLAvEKM.png)

Note that you have set the sender country to "US" and the sender currency to "USD" in the application code. This is why funding the wallet with USD was required in the previous step. 

Because you are using the Rapyd sandbox environment, you can set the account number value to "888********" and the bic_swift value to a random value like "573675777". Then go on filling in the rest of the sender, beneficiary, and transaction details fields. Click the **Send Payment** button once you’re finished, and wait a few seconds for the transaction to be done. The success message will show the payment ID as in the following image. You will need this ID to simulate the payment completion action in the next step.

![Rapyd Disburse SWIFT payout payment ID](https://i.imgur.com/QuyDyfu.png)

> Note: One of the fields that is not required in this example is purpose_code. This field describes the nature of the payout, or what the payout is for. It is only required while sending a payment to one of the following countries: China, India, South Korea, Philippines, and Malaysia. The value of this field can only be one of the following: investment_income, salary, insurance_payments, computer_services, educational_services, payment_of_goods, payment_of_services, or inward_remittance.

### Simulating Payment Complete Webhook Action

When the payout is completed and the beneficiary receives the funds, Rapyd sends a webhook that your application can receive. Rapyd's sandbox does not automatically simulate the action of receiving the payout funds. Instead, the Rapyd Disburse API provides a way for you to simulate the payment completion action. In order to do this, you need to define a URL that receives Rapyd Disburse webhooks in your Rapyd dashboard.

To add a webhook in your Rapyd dashboard, you need to have a live URL for your local server that can be accessed online. You can do this by using a third-party service like [ngrok](https://ngrok.com/). [Create an ngrok account](https://dashboard.ngrok.com/signup) and follow their setup guide to have a live URL for your local server. 

After installing ngrok and following the setup guide from your account dashboard, run `ngrok http 3000` in the terminal window. Then open the **tunnels** tab in your ngrok dashboard to see the live URL that you created. You'll use this URL to create a webhook. Copy the URL followed by the webhook route like this: ```{YOUR-NGROK-URL}/payment-complete```. Paste it into the webhooks page in your Rapyd dashboard, as in the following image, then click “Create”:

![Add Rapyd webhook URL](https://i.imgur.com/AcAzKJi.png)

Once the webhook is created,  click **Edit Webhooks** next to your the newly created webhook, and add the disburse events.

![Edit Rapyd webhook events](https://i.imgur.com/xkYKzMg.png)

The payout will usually be in "Confirmation" status awaiting the confirmation of the FX rate. To confirm the FX rate, run the following request and use the payout ID that you received from the form submission in the “payout” parameter:

```
POST https://sandboxapi.rapyd.net/v1/payouts/confirm/:payout
```

Finally, make sure that your application server and ngrok are running, then perform the payment completion simulation with this request URI:

```
POST https://sandboxapi.rapyd.net/v1/payouts/complete/:payout/:amount
```

Use the same payout ID from the previous request in the “payout” parameter as well as the same payout amount.

Once the request is done successfully, the response will show in your terminal window as coded in the "/payment-complete" route, like this:

![Console payment complete request object](https://i.imgur.com/eRZuRNM.png)

## Conclusion

In this article, you were introduced to the Swift payment method and the capabilities of the Rapyd Disburse API to send payouts using Swift. Then you learned how to create a Node.js server using Express to make an interface and send payouts using the Rapyd Disburse API, as well as how to use webhooks to listen to and confirm payout transactions upon completion.

The [Rapyd Disburse API](https://docs.rapyd.net/build-with-rapyd/docs/payouts) is designed to help your business pay contractors, workers, suppliers, or any other business anywhere in the world. By using the Rapyd Disburse global payout platform, you can reach 100+ countries using a set of payout methods including bank transfers, eWallets, cards, and cash.

Aside from disbursements, Rapyd also provides a range of global payment solutions, including accepting foreign payments, hosted ecommerce checkout pages, receiving and managing escrow payments, managing global subscriptions, and recurring billing.

Have any thoughts or questions? Post them in the [Rapyd Developer Community](https://community.rapyd.net/).