> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.haloinvest.ng/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.haloinvest.ng/_mcp/server.

# Same-bank transfer

POST https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer
Content-Type: application/json

Sends money between two accounts at Halo. The amount is in kobo.

The money leaves `FromAccountNumber`, which must be your pool account or an account your business opened. When it is left out, your pool account is used. Halo adds its fee.

Each request is checked against your per-transaction limit (default 500,000,000 kobo, NGN 5,000,000) and your daily limit (default 5,000,000,000 kobo, NGN 50,000,000). Halo can set different limits for your business. Transfers that are still unconfirmed count toward the daily limit.

Sending a reference you already used returns the outcome recorded for it. Nothing is sent to the bank again, even if the other fields differ. References belong to your business, so another business using the same reference never affects yours.

A 202 means the bank did not prove success or refusal. Do not retry, and never retry with a new reference: the money may already have moved. Check the outcome with check-transaction-status.

Reference: https://docs.haloinvest.ng/api-reference/transfers-and-debits/local-funds-transfer

## Authentication

- `Authorization` header (bearer token, required) — Your Halo partner API key, sent as `Authorization: Bearer <key>`.

## Request

### Body (application/json)

This endpoint expects an object.

- `Amount` (integer, required) — Amount in kobo. Must be greater than 0.
- `ToAccountNumber` (string, required) — The account to credit.
- `RetrievalReference` (string, required) — Your unique reference for this transfer, at most 12 characters.
- `Narration` (string, required) — Narration, at most 100 characters.
- `FromAccountNumber` (string, optional, nullable) — The account to debit. Defaults to your pool account.

## Response

### 200

The bank confirmed the transfer.

- `status` (boolean, required) — True on success, false otherwise.
- `message` (EnvelopeMessage, required) — A short message. On a 422 validation failure it is an object of field names to error lists.
- `status_code` (integer, required) — The HTTP status code.
- `data` (any, optional) — The result. Left out on most errors.

### 202

Outcome unknown. Do not retry. Check the status with this reference.

- `status` (boolean, required) — True on success, false otherwise.
- `message` (EnvelopeMessage, required) — A short message. On a 422 validation failure it is an object of field names to error lists.
- `status_code` (integer, required) — The HTTP status code.
- `data` (any, optional) — The result. Left out on most errors.

## Errors

### 400 Bad Request Error

The bank refused the transfer, or the source account is not yours.

- `status` (boolean, required) — True on success, false otherwise.
- `message` (EnvelopeMessage, required) — A short message. On a 422 validation failure it is an object of field names to error lists.
- `status_code` (integer, required) — The HTTP status code.
- `data` (any, optional) — The result. Left out on most errors.

### 401 Unauthorized Error

The API key is missing or not recognised, or your business is switched off.

- `error` (UnauthorizedErrorError, optional)

### 403 Forbidden Error

The source account is held by Halo for investments and cannot be debited.

- `status` (boolean, required) — True on success, false otherwise.
- `message` (EnvelopeMessage, required) — A short message. On a 422 validation failure it is an object of field names to error lists.
- `status_code` (integer, required) — The HTTP status code.
- `data` (any, optional) — The result. Left out on most errors.

### 422 Unprocessable Entity Error

Over a limit, or the request failed validation.

- `status` (boolean, required) — True on success, false otherwise.
- `message` (EnvelopeMessage, required) — A short message. On a 422 validation failure it is an object of field names to error lists.
- `status_code` (integer, required) — The HTTP status code.
- `data` (any, optional) — The result. Left out on most errors.

### 429 Too Many Requests Error

Too many requests. Wait and try again.

- `status` (boolean, required) — True on success, false otherwise.
- `message` (EnvelopeMessage, required) — A short message. On a 422 validation failure it is an object of field names to error lists.
- `status_code` (integer, required) — The HTTP status code.
- `data` (any, optional) — The result. Left out on most errors.

## Types

### EnvelopeMessage

A short message. On a 422 validation failure it is an object of field names to error lists.

- string
- map from string to list of string

### UnauthorizedErrorError

- `message` (string, optional)

## Examples

### Transfers and debits_localFundsTransfer_example

**Request**

```json
{
  "Amount": 150000,
  "ToAccountNumber": "1100000002",
  "RetrievalReference": "HT0000000001",
  "Narration": "Payment for order 1001"
}
```

**Response**

```json
{
  "status": true,
  "message": "Transfer successful",
  "status_code": 200,
  "data": null
}
```

**SDK Code**

```python Transfers and debits_localFundsTransfer_example
import requests

url = "https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer"

payload = {
    "Amount": 150000,
    "ToAccountNumber": "1100000002",
    "RetrievalReference": "HT0000000001",
    "Narration": "Payment for order 1001"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Transfers and debits_localFundsTransfer_example
const url = 'https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"Amount":150000,"ToAccountNumber":"1100000002","RetrievalReference":"HT0000000001","Narration":"Payment for order 1001"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Transfers and debits_localFundsTransfer_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer"

	payload := strings.NewReader("{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Transfers and debits_localFundsTransfer_example
require 'uri'
require 'net/http'

url = URI("https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}"

response = http.request(request)
puts response.read_body
```

```java Transfers and debits_localFundsTransfer_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}")
  .asString();
```

```php Transfers and debits_localFundsTransfer_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer', [
  'body' => '{
  "Amount": 150000,
  "ToAccountNumber": "1100000002",
  "RetrievalReference": "HT0000000001",
  "Narration": "Payment for order 1001"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Transfers and debits_localFundsTransfer_example
using RestSharp;

var client = new RestClient("https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Transfers and debits_localFundsTransfer_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "Amount": 150000,
  "ToAccountNumber": "1100000002",
  "RetrievalReference": "HT0000000001",
  "Narration": "Payment for order 1001"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Transfers and debits_localFundsTransfer_example

**Request**

```json
{
  "Amount": 150000,
  "ToAccountNumber": "1100000002",
  "RetrievalReference": "HT0000000001",
  "Narration": "Payment for order 1001"
}
```

**Response**

```json
{
  "status": false,
  "message": "The bank has not confirmed this transfer yet. Do not retry; check its status with this reference.",
  "status_code": 202,
  "data": null
}
```

**SDK Code**

```python Transfers and debits_localFundsTransfer_example
import requests

url = "https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer"

payload = {
    "Amount": 150000,
    "ToAccountNumber": "1100000002",
    "RetrievalReference": "HT0000000001",
    "Narration": "Payment for order 1001"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Transfers and debits_localFundsTransfer_example
const url = 'https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"Amount":150000,"ToAccountNumber":"1100000002","RetrievalReference":"HT0000000001","Narration":"Payment for order 1001"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Transfers and debits_localFundsTransfer_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer"

	payload := strings.NewReader("{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Transfers and debits_localFundsTransfer_example
require 'uri'
require 'net/http'

url = URI("https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}"

response = http.request(request)
puts response.read_body
```

```java Transfers and debits_localFundsTransfer_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}")
  .asString();
```

```php Transfers and debits_localFundsTransfer_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer', [
  'body' => '{
  "Amount": 150000,
  "ToAccountNumber": "1100000002",
  "RetrievalReference": "HT0000000001",
  "Narration": "Payment for order 1001"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Transfers and debits_localFundsTransfer_example
using RestSharp;

var client = new RestClient("https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"Amount\": 150000,\n  \"ToAccountNumber\": \"1100000002\",\n  \"RetrievalReference\": \"HT0000000001\",\n  \"Narration\": \"Payment for order 1001\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Transfers and debits_localFundsTransfer_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "Amount": 150000,
  "ToAccountNumber": "1100000002",
  "RetrievalReference": "HT0000000001",
  "Narration": "Payment for order 1001"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.haloinvest.ng/api/banking/transfer/local-fund-transfer")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```