Create Transfer
curl --request POST \
--url https://api.usezentra.com/api/v1/transfers \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amount_minor": 123,
"recipient_account": "<string>",
"recipient_bank_code": "<string>",
"narration": "<string>",
"reference": "<string>",
"currency": "<string>",
"metadata": {}
}
'import requests
url = "https://api.usezentra.com/api/v1/transfers"
payload = {
"amount_minor": 123,
"recipient_account": "<string>",
"recipient_bank_code": "<string>",
"narration": "<string>",
"reference": "<string>",
"currency": "<string>",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
amount_minor: 123,
recipient_account: '<string>',
recipient_bank_code: '<string>',
narration: '<string>',
reference: '<string>',
currency: '<string>',
metadata: {}
})
};
fetch('https://api.usezentra.com/api/v1/transfers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.usezentra.com/api/v1/transfers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount_minor' => 123,
'recipient_account' => '<string>',
'recipient_bank_code' => '<string>',
'narration' => '<string>',
'reference' => '<string>',
'currency' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.usezentra.com/api/v1/transfers"
payload := strings.NewReader("{\n \"amount_minor\": 123,\n \"recipient_account\": \"<string>\",\n \"recipient_bank_code\": \"<string>\",\n \"narration\": \"<string>\",\n \"reference\": \"<string>\",\n \"currency\": \"<string>\",\n \"metadata\": {}\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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.usezentra.com/api/v1/transfers")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount_minor\": 123,\n \"recipient_account\": \"<string>\",\n \"recipient_bank_code\": \"<string>\",\n \"narration\": \"<string>\",\n \"reference\": \"<string>\",\n \"currency\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usezentra.com/api/v1/transfers")
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_minor\": 123,\n \"recipient_account\": \"<string>\",\n \"recipient_bank_code\": \"<string>\",\n \"narration\": \"<string>\",\n \"reference\": \"<string>\",\n \"currency\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"success": false,
"error": {
"code": "insufficient_balance",
"message": "Wallet balance insufficient",
"status": 422,
"details": {
"required": 50050,
"available": 30000
}
}
}
{
"success": false,
"error": {
"code": "invalid_account",
"message": "Recipient account not found",
"status": 422
}
}
{
"success": false,
"error": {
"code": "limit_exceeded",
"message": "Daily transfer limit exceeded",
"status": 422,
"details": {
"limit": 1000000,
"used": 950000
}
}
}
Transfers
Create Transfer
POST /api/v1/transfers - Send money to a bank account
POST
/
api
/
v1
/
transfers
Create Transfer
curl --request POST \
--url https://api.usezentra.com/api/v1/transfers \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amount_minor": 123,
"recipient_account": "<string>",
"recipient_bank_code": "<string>",
"narration": "<string>",
"reference": "<string>",
"currency": "<string>",
"metadata": {}
}
'import requests
url = "https://api.usezentra.com/api/v1/transfers"
payload = {
"amount_minor": 123,
"recipient_account": "<string>",
"recipient_bank_code": "<string>",
"narration": "<string>",
"reference": "<string>",
"currency": "<string>",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
amount_minor: 123,
recipient_account: '<string>',
recipient_bank_code: '<string>',
narration: '<string>',
reference: '<string>',
currency: '<string>',
metadata: {}
})
};
fetch('https://api.usezentra.com/api/v1/transfers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.usezentra.com/api/v1/transfers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount_minor' => 123,
'recipient_account' => '<string>',
'recipient_bank_code' => '<string>',
'narration' => '<string>',
'reference' => '<string>',
'currency' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.usezentra.com/api/v1/transfers"
payload := strings.NewReader("{\n \"amount_minor\": 123,\n \"recipient_account\": \"<string>\",\n \"recipient_bank_code\": \"<string>\",\n \"narration\": \"<string>\",\n \"reference\": \"<string>\",\n \"currency\": \"<string>\",\n \"metadata\": {}\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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.usezentra.com/api/v1/transfers")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount_minor\": 123,\n \"recipient_account\": \"<string>\",\n \"recipient_bank_code\": \"<string>\",\n \"narration\": \"<string>\",\n \"reference\": \"<string>\",\n \"currency\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usezentra.com/api/v1/transfers")
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_minor\": 123,\n \"recipient_account\": \"<string>\",\n \"recipient_bank_code\": \"<string>\",\n \"narration\": \"<string>\",\n \"reference\": \"<string>\",\n \"currency\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"success": false,
"error": {
"code": "insufficient_balance",
"message": "Wallet balance insufficient",
"status": 422,
"details": {
"required": 50050,
"available": 30000
}
}
}
{
"success": false,
"error": {
"code": "invalid_account",
"message": "Recipient account not found",
"status": 422
}
}
{
"success": false,
"error": {
"code": "limit_exceeded",
"message": "Daily transfer limit exceeded",
"status": 422,
"details": {
"limit": 1000000,
"used": 950000
}
}
}
Initiate a money transfer to any Nigerian bank account.
Endpoint
POST /api/v1/transfers
Request Body
Amount in kobo (e.g., 10000 = ₦100.00)
Recipient account number (10 digits)
Recipient bank code (e.g.,
058 for GTBank)Transfer description (max 100 characters)
Unique reference for this transfer (auto-generated if not provided)
Currency code (currently only NGN supported)
Additional data to store with the transfer
Response
Unique transfer ID
Transfer amount in kobo
Transaction fee in kobo
Total amount debited (amount + fee)
Recipient account number
Recipient account name
Recipient bank name
Transfer status (
pending, processing, completed, failed)Unique reference
Transfer description
Provider session ID
ISO 8601 timestamp
Example Request
const transfer = await client.transfers.create({
amountMinor: 50000, // ₦500.00
recipient_account: '0123456789',
recipient_bank_code: '058',
narration: 'Payment for services',
reference: 'TRF_' + Date.now(),
metadata: {
customer_id: 'cus_123',
invoice_id: 'INV_456'
}
});
console.log(`Transfer ID: ${transfer.id}`);
console.log(`Status: ${transfer.status}`);
transfer = client.transfers.create(
amount_minor=50000, # ₦500.00
recipient_account='0123456789',
recipient_bank_code='058',
narration='Payment for services',
reference=f'TRF_{int(time.time())}',
metadata={
'customer_id': 'cus_123',
'invoice_id': 'INV_456'
}
)
print(f"Transfer ID: {transfer.id}")
print(f"Status: {transfer.status}")
$transfer = $client->transfers->create([
'amount_minor' => 50000, // ₦500.00
'recipient_account' => '0123456789',
'recipient_bank_code' => '058',
'narration' => 'Payment for services',
'reference' => 'TRF_' . time(),
'metadata' => [
'customer_id' => 'cus_123',
'invoice_id' => 'INV_456'
]
]);
echo "Transfer ID: {$transfer->id}\n";
echo "Status: {$transfer->status}";
curl -X POST https://api.usezentra.com/api/v1/transfers \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount_minor": 50000,
"recipient_account": "0123456789",
"recipient_bank_code": "058",
"narration": "Payment for services",
"reference": "TRF_1234567890",
"metadata": {
"customer_id": "cus_123",
"invoice_id": "INV_456"
}
}'
Example Response
{
"success": true,
"data": {
"id": "trn_abc123xyz",
"amount_minor": 50000,
"fee_minor": 50,
"total_minor": 50050,
"recipient_account": "0123456789",
"recipient_name": "John Doe",
"recipient_bank": "Guaranty Trust Bank",
"recipient_bank_code": "058",
"status": "pending",
"reference": "TRF_1234567890",
"narration": "Payment for services",
"session_id": "SES_xyz789",
"currency": "NGN",
"metadata": {
"customer_id": "cus_123",
"invoice_id": "INV_456"
},
"created_at": "2024-01-15T10:30:00Z"
}
}
Transfer Fees
| Amount Range | Fee |
|---|---|
| ₦0 - ₦5,000 | ₦10 |
| ₦5,001 - ₦50,000 | ₦25 |
| Above ₦50,000 | ₦50 |
Fees are automatically deducted from your wallet balance.
Processing Time
- Instant: Most transfers complete within seconds
- Same Day: Some banks may take up to 24 hours
- Webhook: You’ll receive a webhook when the transfer completes
Error Responses
{
"success": false,
"error": {
"code": "insufficient_balance",
"message": "Wallet balance insufficient",
"status": 422,
"details": {
"required": 50050,
"available": 30000
}
}
}
{
"success": false,
"error": {
"code": "invalid_account",
"message": "Recipient account not found",
"status": 422
}
}
{
"success": false,
"error": {
"code": "limit_exceeded",
"message": "Daily transfer limit exceeded",
"status": 422,
"details": {
"limit": 1000000,
"used": 950000
}
}
}
Idempotency
Use thereference parameter to prevent duplicate transfers:
// This will only create one transfer, even if called multiple times
const transfer = await client.transfers.create({
amountMinor: 50000,
destinationAccountNumber: '0123456789',
destinationBankCode: '058',
narration: 'Payment',
reference: 'UNIQUE_REF_123' // Use same reference
});
Next Steps
Get Transfer
Check transfer status
List Transfers
View all transfers
Resolve Account
Verify account before sending
Webhooks
Handle transfer events
Was this page helpful?
⌘I