> ## Documentation Index
> Fetch the complete documentation index at: https://flutterwaveinc.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> Learn how to use Flutterwave account to send money across other accounts.

You can make transfers (also called payouts) individually or in bulk from your Flutterwave available balance. You can transfer to a bank account, a mobile money account, or another Flutterwave account.

This document explains a few things you need to know about transfers in general. You should read this first, and then you can view examples for specific types of transfers on their respective pages:

1. [Bank Accounts](/fund-transfer/bank-account)
2. [Mobile Money](/fund-transfer/mobile-money)
3. [Wallet-to-Wallet](/fund-transfer/wallet-to-wallet)
4. [Bulk Transfers](/fund-transfer/bulk-transfer)
5. [Cash Pickup](/fund-transfer/cash-pickup)

<Info>
  You can transfer money to the following countries with Flutterwave:

  Nigeria, United States, The United Kingdom, Canada, Ghana, Kenya, Uganda, Tanzania, South Africa, Zambia, Cameroon, Ivory Coast, Sierra Leone, Burkina Faso, Guinea-Bissau, Mali, Senegal, Rwanda, Tunisia, Guinea Conakry and over 30 other Countries.

  See our [support docs](https://flutterwave.com/ng/support/payments/what-currencies-can-you-transfer-to) for details.
</Info>

## How Transfers Work

You can make a transfer directly from your [dashboard](https://flutterwave.com/ng/support/payments/how-to-make-a-transfer-single-or-bulk) or by using the transfer APIs.

Making a transfer via API looks like this. You make a POST request to our [create transfer endpoint](/api-reference/transfers/initiate-a-transfer). The details will vary depending on the type of transfer, but you'll typically need to specify an `amount`, `currency`, `account_bank`, and `account_number`.

You can also specify:

* A `narration` describing the transfer,
* A unique `reference` code to identify the transfer (if you don't supply one, we'll generate one for you).
* A `meta`, for any extra information you want to record about the transfer, for example: `"meta": {"quantity": "24", "goods_received_at": "24/02/21"}`.

<CodeGroup>
  ```javascript Node.js theme={null}
  // Install with: npm i flutterwave-node-v3

  const Flutterwave = require('flutterwave-node-v3');
  const flw = new Flutterwave(
  	process.env.FLW_PUBLIC_KEY,
  	process.env.FLW_SECRET_KEY
  );
  const details = {
  	account_bank: '044',
  	account_number: '1234567840',
  	amount: 200,
  	currency: 'NGN',
  	narration: 'Payment for things',
  	reference: generateTransactionReference(),
  };
  flw.Transfer.initiate(details).then(console.log).catch(console.log);
  ```

  ```php PHP theme={null}
  // Install with: composer require flutterwavedev/flutterwave-v3

  $flw = new \Flutterwave\Rave(getenv('FLW_SECRET_KEY')); // Set `PUBLIC_KEY` as an environment variable
  $transferService = new \Flutterwave\Transfer();
  $details = [
      "account_bank" => "044",
      "account_number" => "1234567840",
      "amount" => 200,
      "narration" => "Payment for things",
      "currency" => "NGN",
      "reference" => generateTransactionReference(),
  ];
  $response = $transferService->singleTransfer($details);
  ```

  ```ruby Ruby theme={null}
  # Install with: gem install flutterwave_sdk

  require 'flutterwave_sdk'

  flw = Flutterwave.new(ENV["FLW_PUBLIC_KEY"], ENV["FLW_SECRET_KEY"], ENV["FLW_ENCRYPTION_KEY"])
  transfer = Transfer.new(flw)
  details = {
      account_bank: "044",
      account_number: "1234567840",
      amount: 200,
      narration: "Payment for things",
      currency: "NGN",
      reference: generate_transaction_reference,
  }
  response = transfer.initiate_transfer details
  print response
  ```

  ```python Python theme={null}
  # Install with: pip install rave_python

  import os
  from rave_python import Rave

  rave = Rave(os.getenv("FLW_PUBLIC_KEY"), os.getenv("FLW_SECRET_KEY"))
  details = {
      "account_bank": "044",
      "account_number": "1234567840",
      "amount": 200,
      "narration": "Payment for things",
      "currency": "NGN",
      "reference": generate_transaction_reference(),
  }
  res = rave.Transfer.initate(details)
  print(res)
  ```

  ```go Go theme={null}
  // Install with: go get github.com/Flutterwave/Rave-go/rave

  import (
    "fmt"
    "os"
    "github.com/Flutterwave/Rave-go/rave"
  )
  var r = rave.Rave{
    false,
    os.Getenv("FLW_PUBLIC_KEY"),
    os.Getenv("FLW_SECRET_KEY"),
  }
  var transfer = rave.Transfer{
      r,
  }
  details := rave.SinglePaymentData {
      AccountBank:   "044",
      AccountNumber: "1234567844",
      Amount:        500,
      Narration:     "Payment for things",
      Currency:      "NGN",
      Reference:     GenerateTransactionReference(),
  }
  err, response := transfer.InitiateSingleTransfer(details)
  if err != nil {
      panic(err)
  }
  fmt.Println(response)
  ```

  ```json cURL theme={null}
  curl --request POST 'https://api.flutterwave.com/v3/transfers' \
    --header 'Authorization: Bearer YOUR_SECRET_KEY' \
    --header 'Content-Type: application/json' \
    --data-raw '{
      "account_bank": "044",
      "account_number": "1234567840",
      "amount": 200,
      "narration": "Payment for things",
      "currency": "NGN",
      "reference": "jh678b3kol1Z"
  }'
  ```
</CodeGroup>

<Note>
  **Cross-currency Transfers**

  By default, we'll debit your balance matching the transfer currency e.g. for
  a 200 GHS transfer, we'll debit your GHS balance. You can override this by using
  the `debit_currency` field.
</Note>

```javascript Sample Request theme={null}
await flw.Transfer.initiate({
    account_bank: "044",
    account_number: "1234567840",
    amount: 200,
    currency: "GHS", // destination currency
    debit_currency: "NGN" // source or wallet to debit for the transfer.
});
```

You can use the [transfer rates](/api-reference/transfers/get-transfer-rates) endpoint to get the current rate we'll use when converting between currencies.

## Handling the Response

After creating a transfer, you'll get a response like this:

<CodeGroup>
  ```json 200 OK theme={null}
  {
  	"status": "success",
  	"message": "Transfer Queued Successfully",
  	"data": {
  		"id": 190626,
  		"account_number": "1234567840",
  		"bank_code": "044",
  		"full_name": "Alexis Sanchez",
  		"created_at": "2021-04-26T11:19:55.000Z",
  		"currency": "NGN",
  		"debit_currency": "NGN",
  		"amount": 200,
  		"fee": 10.75,
  		"status": "NEW",
  		"reference": "jh678b3kol1Z",
  		"meta": null,
  		"narration": "Payment for things",
  		"complete_message": "",
  		"requires_approval": 0,
  		"is_approved": 1,
  		"bank_name": "ACCESS BANK NIGERIA"
  	}
  }
  ```

  ```json 400 Error theme={null}
  {
    "status": "error"
    "message": "Transfer creation failed"
    "data": {
      "id": 190874
      "account_number": "1234567840"
      "bank_code": "044"
      "full_name": "N/A"
      "created_at": "2021-04-28T14:49:42.000Z"
      "currency": "NGN"
      "debit_currency": "USD"
      "amount": 5500
      "fee": 26.875
      "status": "FAILED"
      "reference": "f2a321a89ab2c652"
      "meta": null,
      "narration": "Payment for goods purchased"
      "complete_message": "Beneficiary not found"
      "requires_approval": 0
      "is_approved": 1
      "bank_name": "N/A"
    }
  }
  ```
</CodeGroup>

There are some important details here:

* `data.id` is the ID of the transfer. You can use this ID to fetch details about this transfer later.

* `data.status` is the status of the transfer. `data.complete_message` is a friendly explanation of the status.

  * For a new transfer, the status is `"NEW"`. The `complete_message` is typically empty.
  * A status of `"PENDING"` means that the transfer is being processed. The `complete_message` might be `"Transaction is currently being processed"`.
  * When the transfer is completed, the status changes to `SUCCESSFUL`. The `complete_message` might be `"Transaction was successful"`.
  * If the transfer fails, the status changes to `FAILED`. The `complete_message` would contain the failure reason, such as `"Account resolve failed"`.

If a transfer fails, you can retry it with the [retry transfer endpoint](/api-reference/transfers/retry-a-transfer).

## Checking the Status of the Transfer

There are three ways to find out the status of a transfer:

1. If you have [webhooks](/webhooks) enabled, we'll call your webhook URL with the transfer details when the transfer is completed or fails.

2. If you specified a `callback_url` when creating the transfer, we'll call that URL with the transfer details when the transfer is completed or fails.

```javascript Sample Request theme={null}
await flw.Transfer.initiate({
  account_bank: "044",
  account_number: "1234567840",
  amount: 200,
  currency: "NGN",
+ callback_url: 'http://my-callback-url'
})
```

3. You can manually check the current status of the transfer by calling the [get transfer endpoint](/api-reference/transfers/fetch-a-transfer) with the transfer ID

Here's what the webhook/callback payload looks like:

<CodeGroup>
  ```json Successful  theme={null}
    {
    "event": "transfer.completed",
    "event.type": "Transfer",
    "data": {
      "id": 8416497,
      "account_number": "******",
      "bank_name": "ACCESS BANK NIGERIA",
      "bank_code": "044",
      "fullname": "John Doe",
      "created_at": "2021-04-28T17:01:41.000Z",
      "currency": "NGN",
      "debit_currency": "NGN",
      "amount": 100,
      "fee": 10.75,
      "status": "SUCCESSFUL",
      "reference": "TX-refe123456-6-3-1",
      "meta": null,
      "narration": "Test for wallet to wallet",
      "approver": null,
      "complete_message": "Transaction was successful",
      "requires_approval": 0,
      "is_approved": 1
    }
  }
  ```

  ```json Failed theme={null}
  {
  	"event": "transfer.completed",
  	"event.type": "Transfer",
  	"data": {
  		"id": 8416559,
  		"account_number": "********",
  		"bank_name": "ACCESS BANK NIGERIA",
  		"bank_code": "044",
  		"fullname": "John Doe",
  		"created_at": "2021-04-28T17:04:17.000Z",
  		"currency": "NGN",
  		"debit_currency": "NGN",
  		"amount": 10000,
  		"fee": 26.875,
  		"status": "FAILED",
  		"reference": "TX-refe123456-6-3-2",
  		"meta": null,
  		"narration": "Test for wallet to wallet",
  		"approver": null,
  		"complete_message": "DISBURSE FAILED: Insufficient funds in customer wallet",
  		"requires_approval": 0,
  		"is_approved": 1
  	}
  }
  ```
</CodeGroup>

Here's how you can check using the [get transfer endpoint](/api-reference/transfers/fetch-a-transfer):

<CodeGroup>
  ```javascipt Node.js theme={null}
  const response = await flw.Transfer.get_a_transfer({id: transferId});
  ```

  ```ruby Ruby theme={null}
  response = transfer.get_a_transfer transfer_id
  ```

  ```json cURL theme={null}
  curl --request GET 'https://api.flutterwave.com/v3/transfers/:YOUR_TRANSFER_ID' \
    --header 'Authorization: Bearer YOUR_SECRET_KEY'
  ```
</CodeGroup>

## Checking the Transfer Fee

After making a transfer, the `fee` you were charged is indicated in the fee field of the response. You can check how much you'll be charged before making the transfer by using the [get transfer fee endpoint](/api-reference/transfers/get-transfer-fee). You'll need to specify the amount, currency, and type of transfer (`mobilemoney`, `barter`, or `account`).

<Note>Transfers to other Flutterwave merchants are free.</Note>

For example, if you wish to transfer 2700 EUR to a bank account, you'd make this request:

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await flw.Transfer.fee({
    type: "account",
    amount: 2700,
    currency: "EUR",
  });
  ```

  ```php PHP theme={null}
  $response = $transferService->getTransferFee([
      "amount" => 2700,
      "type" => "account",
      "currency" => "EUR",
  ]);
  ```

  ```ruby Ruby theme={null}
  response = transfer.transfer_fee {
      type: "account",
      amount: 2700,
      currency: "EUR",
  }
  ```

  ```json cURL theme={null}
  curl --request GET 'https://api.flutterwave.com/v3/transfers/fee' \
    --header 'Authorization: Bearer YOUR_SECRET_KEY' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "type": "account",
        "amount": 2700,
        "currency": "EUR"
  }'
  ```
</CodeGroup>

You'll get a response like this:

```json theme={null}
{
	"status": "success",
	"message": "Transfer fee fetched",
	"data": [
		{
			"currency": "EUR",
			"fee_type": "value",
			"fee": 35
		}
	]
}
```

This means you'll be charged 35 EUR for this transfer.

## Beneficiaries

After making a transfer, the destination account details are saved as a new beneficiary. You can then use the beneficiary ID as a shortcut to make a transfer to the same account in the future, allowing you to skip specifying the account details.

<CodeGroup>
  ```javascript Node.js theme={null}
  await flw.Transfer.initiate({
      beneficiary: 7758,
      amount: 200,
      currency: "NGN",
  });
  ```

  ```php PHP theme={null}
  $transferService->singleTransfer([
      "beneficiary" => 7758,
      "amount" => 200,
      "currency" => "NGN",
  ]);
  ```

  ```ruby Ruby theme={null}
  transfer.initiate_transfer({
  +   beneficiary: 7758,
      amount: 200,
      currency: "NGN",
  })
  ```

  ```python Python theme={null}
  rave.Transfer.initate({
      "beneficiary": 7758,
      "amount": 200,
      "currency": "NGN",
  })
  ```

  ```go Go theme={null}
  transfer.InitiateSingleTransfer(rave.SinglePaymentData {
      Beneficiary:   7758,
      Amount:        500,
      Currency:      "NGN",
  })
  ```

  ```json cURL theme={null}
  curl --request POST 'https://api.flutterwave.com/v3/transfers' \
    --header 'Authorization: Bearer YOUR_SECRET_KEY' \
    --header 'Content-Type: application/json' \
    --data-raw '{
      "beneficiary": 7758,
      "amount": 200,
      "currency": "NGN"
  }'
  ```
</CodeGroup>

You can manage your saved beneficiaries with the API: you can [add beneficiaries](/api-reference/beneficiaries/create-a-transfer-beneficiary) at any time, [fetch one](/api-reference/beneficiaries/fetch-a-transfer-beneficiary) or [all beneficiary details](/api-reference/beneficiaries/list-all-transfer-beneficiaries), and [delete a beneficiary](/api-reference/beneficiaries/delete-a-transfer-beneficiary).

## Verifying Account Details

You can fetch a destination account's details before making a transfer. While this isn't required, it can be helpful to confirm that the details were entered correctly and that the transfer is going to the intended recipient.

Verification is supported for Nigerian bank accounts, and Flutterwave merchant IDs. See our guide to [bank account verification](/verifications-kyc/bank-account-verification) for details.

## Testing Transfers

<Warning>
  **IP Whitelisting**

  In order to conduct a successful integration test, it's important to ensure that you whitelist the IP addresses of the servers making the transfer API calls
</Warning>

You can find test credentials and mock data for your Integration tests in the [testing helpers](/testing#testing-transfers) section.

## Next Steps

Before you go live with your integration, be sure to check out our [Integration Guide](/best-practices) for extra guidelines. If you ever find yourself stuck, don't hesitate to reach out to our [dedicated support](https://flutterwave.com/ng/support/submit-request) team for assistance.
