Setting up Cross-Border Payments in a Single Codebase

Adding support for cross-border payments sounds simple until you start implementing. One API works for Nigeria, but Ghana requires a different format. Kenya adds another layer with unique bank codes and payout rules. Then you realize exchange rates change every few minutes, and if you don't refresh them at the right time, you'd have to cover the loss. You end up maintaining separate logic for each country, duplicating flows that should have been shared, and introducing edge cases that only show up in production. The more countries you add, the harder it gets to keep the system reliable. A single codebase solves this by letting you manage different currencies, payout methods, and compliance checks in one place. It helps you reduce complexity, cut down maintenance work, and ship new regions without breaking old ones. In this guide, you'll learn how to build a cross-border payment system with Flutterwave that works across Nigeria, Ghana, and Kenya without duplicating logic or fragmenting your codebase. You'll fetch live FX rates, verify account details, collect payments in foreign currencies, and send funds locally from one integrated setup. But first, let’s walk through what makes a payment “cross-border” and why that changes how you build. What are Cross-Border Payments? Cross-border payments are financial transactions between two parties, a sender and a recipient, located in different countries. These transactions involve transferring funds through banks or other financial institutions. They may require currency conversion and support multiple payment methods. Both individuals and businesses can initiate cross-border payments for different reasons. These transactions generally fall into the following categories: Remittances: Individuals can send money to family and friends abroad. This increases cash flow in the recipient’s country and contributes to economic development. Investments: Investors can purchase assets such as bonds, stocks, and real estate in other countries and receive returns on their investments. Salaries and Taxes: Businesses can pay salaries, taxes, and employee benefits, such as insurance, to workers living in other countries. International Trade: Businesses can pay suppliers for goods and services and receive payments from international customers. Travel and Tourism: Travelers can pay for hotels, flights, and other services when visiting foreign countries. In these types of international payments, the ideal payment method depends on factors such as transaction fees, the currencies involved, and the transaction amount. Individuals and businesses have a range of options to choose from, each with its own advantages. These include credit or debit card transactions for convenience and speed, international money orders for more traditional transfers, and online payment platforms that offer user-friendly interfaces and a wider reach. Electronic fund transfers, bank account transfers, and wire transfers remain reliable choices for larger or more formal payments. Benefits of Cross-Border Payments For businesses looking to expand globally, cross-border payments offer several advantages: Diversification: Businesses can reduce reliance on domestic markets and expand their investment portfolios by reaching new customers and suppliers. Increased Revenue: Selling goods and services internationally creates new revenue streams and business opportunities. Access to Global Markets: Businesses can connect with international customers, partners, and suppliers. Payment Flexibility: Companies can offer multiple payment methods, making transactions more convenient and improving reconciliation processes. Important Considerations for International Transfers Despite their benefits, cross-border payments also present challenges that businesses must navigate: Fraud and Security Risks: International transactions increase exposure to cyberattacks, payment scams, and identity theft. Regulatory Compliance: Meeting cross-border payment regulations and compliance requirements can be complex and time-consuming. Fees and Charges: Some payment methods and regions impose high transaction fees, affecting overall costs. Currency Risk: Exchange rate fluctuations can impact transaction values and business cash flow. Operational Overhead: Cross-border payments require more resources and time than domestic transactions, making them more complex to manage. Cross-border payments have transformed how businesses operate, but they come with challenges for individuals and companies. These challenges become even more complex when building a fintech app that offers cross-border payments as a service. As a fintech builder, you might ask yourself if you need to write country-specific code or if you can extend your existing codebase. Compliance is another major consideration, and that is just the beginning. But what if you could extend your existing codebase or

Apr 15, 2025 - 11:24
 0
Setting up Cross-Border Payments in a Single Codebase

Adding support for cross-border payments sounds simple until you start implementing. One API works for Nigeria, but Ghana requires a different format. Kenya adds another layer with unique bank codes and payout rules. Then you realize exchange rates change every few minutes, and if you don't refresh them at the right time, you'd have to cover the loss.

You end up maintaining separate logic for each country, duplicating flows that should have been shared, and introducing edge cases that only show up in production. The more countries you add, the harder it gets to keep the system reliable.

A single codebase solves this by letting you manage different currencies, payout methods, and compliance checks in one place. It helps you reduce complexity, cut down maintenance work, and ship new regions without breaking old ones.

In this guide, you'll learn how to build a cross-border payment system with Flutterwave that works across Nigeria, Ghana, and Kenya without duplicating logic or fragmenting your codebase. You'll fetch live FX rates, verify account details, collect payments in foreign currencies, and send funds locally from one integrated setup.

But first, let’s walk through what makes a payment “cross-border” and why that changes how you build.

What are Cross-Border Payments?

Cross-border payments are financial transactions between two parties, a sender and a recipient, located in different countries. These transactions involve transferring funds through banks or other financial institutions. They may require currency conversion and support multiple payment methods.

Both individuals and businesses can initiate cross-border payments for different reasons. These transactions generally fall into the following categories:

  • Remittances: Individuals can send money to family and friends abroad. This increases cash flow in the recipient’s country and contributes to economic development.
  • Investments: Investors can purchase assets such as bonds, stocks, and real estate in other countries and receive returns on their investments.
  • Salaries and Taxes: Businesses can pay salaries, taxes, and employee benefits, such as insurance, to workers living in other countries.
  • International Trade: Businesses can pay suppliers for goods and services and receive payments from international customers.
  • Travel and Tourism: Travelers can pay for hotels, flights, and other services when visiting foreign countries.

In these types of international payments, the ideal payment method depends on factors such as transaction fees, the currencies involved, and the transaction amount. Individuals and businesses have a range of options to choose from, each with its own advantages. These include credit or debit card transactions for convenience and speed, international money orders for more traditional transfers, and online payment platforms that offer user-friendly interfaces and a wider reach. Electronic fund transfers, bank account transfers, and wire transfers remain reliable choices for larger or more formal payments.

Benefits of Cross-Border Payments

For businesses looking to expand globally, cross-border payments offer several advantages:

  • Diversification: Businesses can reduce reliance on domestic markets and expand their investment portfolios by reaching new customers and suppliers.
  • Increased Revenue: Selling goods and services internationally creates new revenue streams and business opportunities.
  • Access to Global Markets: Businesses can connect with international customers, partners, and suppliers.
  • Payment Flexibility: Companies can offer multiple payment methods, making transactions more convenient and improving reconciliation processes.

Important Considerations for International Transfers

Despite their benefits, cross-border payments also present challenges that businesses must navigate:

  • Fraud and Security Risks: International transactions increase exposure to cyberattacks, payment scams, and identity theft.
  • Regulatory Compliance: Meeting cross-border payment regulations and compliance requirements can be complex and time-consuming.
  • Fees and Charges: Some payment methods and regions impose high transaction fees, affecting overall costs.
  • Currency Risk: Exchange rate fluctuations can impact transaction values and business cash flow.
  • Operational Overhead: Cross-border payments require more resources and time than domestic transactions, making them more complex to manage.

Cross-border payments have transformed how businesses operate, but they come with challenges for individuals and companies. These challenges become even more complex when building a fintech app that offers cross-border payments as a service.

As a fintech builder, you might ask yourself if you need to write country-specific code or if you can extend your existing codebase. Compliance is another major consideration, and that is just the beginning.

But what if you could extend your existing codebase or even use a single codebase to process cross-border payments? Before exploring how that works, it is important to understand why using a single codebase matters.

Implementing Cross-Border Payments with Flutterwave

Let’s consider a scenario where your customers live in the diaspora and want to use your fintech app to process funds in Nigeria, Kenya, and Ghana.

To build a solution that supports cross-border payments, follow these steps:

Cross-Border Payment

Step 1: Get the Live Exchange Rate

When building a cross-border payment system, you don’t want customers guessing exchange rates or doing manual calculations. Use the query transfer rate endpoint to display the current rate before they initiate and confirm a transfer. This builds trust and prevents surprises.

For example, if a customer wants to send the Naira equivalent of 1,000 USD to a family member in Nigeria using Access Bank (0690000032), make a request to the query transfer rate endpoint by specifying the amount, destination_currency, and source_currency:

curl --request GET \
      --url 'https://api.flutterwave.com/v3/transfers/rates?amount=1000&destination_currency=USD&source_currency=NGN' \
      --header 'Authorization: Bearer ' \
      --header 'Content-Type: application/json' \
      --header 'accept: application/json'

In the request above, the destination_currency is set to USD because Flutterwave uses it to determine the current exchange rate against the source currency (NGN).

You’ll get a response with the current exchange rate and the equivalent amount.

{
    "status": "success",
    "message": "Transfer amount fetched",
    "data": {
        "rate": 1548.1648,
        "source": {
            "currency": "NGN",
            "amount": 1548164.8
        },
        "destination": {
            "currency": "USD",
            "amount": 1000
        }
    }
}

Note the amount, as you’ll need it to process the transfer.

As a best practice, display a countdown timer and query the endpoint at specific intervals. This improves the user experience by keeping exchange rates accurate.

Step 2: Get the Bank Code

You need the bank code to initiate a transfer with Flutterwave. Bank codes are unique identifiers that every bank has.

To get a bank code in Nigeria for example:

curl --request GET \
      --url https://api.flutterwave.com/v3/banks/NG \
      --header 'Authorization: Bearer ' \
      --header 'Content-Type: application/json' \
      --header 'accept: application/json'

You’ll get a response similar to this:

{
  "status": "success",
  "message": "Banks fetched successfully",
  "data": [
    {
      "id": "bnk_cYjd92Qk",
      "code": "044",
      "name": "Access Bank"
    }
    .......
  ]
}

Step 3: Verify the Bank Details

Use the retrieve bank account name endpoint to verify the account details and to confirm that funds are being transferred to the correct account. This helps you reduce disputes and chargebacks.

The retrieve bank account name endpoint only works for Nigerian bank accounts. For bank accounts in other countries, it's best to validate and sanitize the inputs, and mask sensitive details when necessary.

curl --request POST \
      --url https://api.flutterwave.com/v3/accounts/resolve \
      --header 'Authorization: Bearer ' \
      --header 'Content-Type: application/json' \
      --header 'accept: application/json' \
      --data '
{
  "account_number": "0690000032",
  "account_bank": "044"
}
'

If the account is valid, you’ll get a response similar to this:

{
    "status": "success",
    "message": "Account details fetched",
    "data": {
        "account_number": "0690000032",
        "account_name": "Pastor Bright"
    }
}

Step 4: Collect Funds From the Customer

Once you've retrieved the exchange rate and confirmed the account details, the next step is to collect the payment from the customer in their preferred currency (USD in this case) using a payment gateway.

Flutterwave offers multiple ways to process payments, including Flutterwave Inline, HTML Checkout, or Flutterwave Standard. Below is an example using Flutterwave Inline, which provides a seamless checkout experience directly within your app.

Example of using Flutterwave Inline:

a. Add the Library: Include the Flutterwave Inline script in your project:

<script src='https://checkout.flutterwave.com/v3.js'></script>

b. Call the FlutterwaveCheckout Function: On your checkout page, trigger the payment flow using the FlutterwaveCheckout() function:

FlutterwaveCheckout({
    public_key: '',
    tx_ref: '',
    amount: 1000,
    currency: 'USD',
    payment_options: 'card, banktransfer, credit',
    redirect_url: 'https://sample-redirect-url.com',
    meta: {
        consumer_id: 23,
        consumer_mac: '92a3-912ba-1192a',
    },
    customer: {
        email: 'john.doe@gmail.com',
        phone_number: '+1 (684) 564-8467',
        name: 'John Doe',
    },
    customizations: {
        title: 'Cross-Border Transfer to Nigeria',
        description: 'Monthly upkeep',
        logo: 'https://www.logolynx.com/images/logolynx/22/2239ca38f5505fbfce7e55bbc0604386.jpeg',
    },
});
**Required Parameters:**
- `public_key`: Your Flutterwave public key.
- `tx_ref`: A unique transaction reference.
- `amount`: The amount to be paid.
- `currency`: The transaction currency. Flutterwave supports over a hundred different currencies.
- `customer`: Customer details (email, phone, name).
**Optional Parameters:**
- `payment_options`: Specifies supported payment methods (e.g., Card, Bank Transfer, Credit Payment).
- `customizations`: Allows you to personalize the checkout experience.

Once the customer initiates a payment, they are redirected to the specified redirect_url with transaction details appended as query parameters:

tx_ref=ref&transaction_id=30490&status=successful

c. Verify the Transaction on your Backend: To confirm a successful payment, verify it using the transaction ID. Only mark the payment as received when the response shows that the full amount was transferred successfully.

curl --request GET 'https://api.flutterwave.com/v3/transactions/30490/verify' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer '

A successful response will look like this:

{
    "status": "success",
    "message": "Transaction fetched successfully",
    "data": {
        "id": 1163068,
        "tx_ref": "akhlm-pstmn-blkchrge-xx6",
        "flw_ref": "FLW-M03K-02c21a8095c7e064b8b9714db834080b",
        "device_fingerprint": "N/A",
        "amount": 1000,
        "currency": "USD",
        "charged_amount": 1000,
        "app_fee": 1,
        "merchant_fee": 0,
        "processor_response": "Approved",
        "auth_model": "noauth",
        "ip": "pstmn",
        "narration": "Monthly upkeep",
        "status": "successful",
        "payment_type": "card",
        "created_at": "2020-03-11T19:22:07.000Z",
        "account_id": 73362,
        "amount_settled": 1000,
        "card": {
            "first_6digits": "553188",
            "last_4digits": "2950",
            "issuer": " CREDIT",
            "country": "United State of America US",
            "type": "MASTERCARD",
            "token": "flw-t1nf-f9b3bf384cd30d6fca42b6df9d27bd2f-m03k",
            "expiry": "09/28"
        },
        "customer": {
            "email": "john.doe@gmail.com",
            "phone_number": "+1 (684) 564-8467",
            "name": "John Doe"
        }
    }
}

Step 5: Make a Transfer Request
Now that the funds are in your Flutterwave USD balance, the next step is to transfer them to the recipient’s account in Nigeria. You can do this using the create a transfer endpoint, which allows you to specify the recipient’s details and transfer amount.

curl --location --request POST 'https://api.flutterwave.com/v3/transfers' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ' \
--data-raw '{
    "account_bank": "044",
    "account_number": "0690000032",
    "amount": 1548164.8,
    "narration": "Pastor Bright",
    "currency": "NGN",
    "reference": "akhlm-pstmnpyt-rfxx007_PMCKDU_1",
    "callback_url": "https://YOUR_SAMPLE_WEBHOOK_URL",
    "debit_currency": "USD"
}'

The key parameters to note are:

  • amount: The equivalent amount in NGN based on the current exchange rate you calculated earlier.
  • debit_currency: Specifies that Flutterwave should charge your USD wallet for the converted NGN amount.

Step 6: Monitor the Transfer Status

You can check the transfer status using one of the following methods:

  • Retrieve Transfer Endpoint: Make a request to the verify transaction endpoint directly to get the transfer status.
  • Webhook (Recommended): Set up a webhook to receive real-time updates.
  • Callback URL: Use a callback URL, if available, to handle status updates automatically.

Handling Compliance and Security

Cross-border payments must comply with regulations like PCI-DSS for card transactions and local anti-money laundering (AML) laws. Flutterwave handles these security and compliance requirements, reducing the burden on your business.

For example, Flutterwave supports Strong Customer Authentication (SCA), encryption, and tokenization, keeping transactions secure without adding code complexity.

Wrapping Up

Setting up cross-border payment services in a single codebase simplifies international expansion while keeping your fintech app scalable and maintainable. Flutterwave’s global payment infrastructure allows developers to support multiple currencies, adapt to regional payment preferences, and stay compliant using a unified API.

For fintech teams expanding beyond one country, Flutterwave provides a flexible and reliable way to handle international transactions with minimal development effort. Get started with Flutterwave today.