Transfers API
The Transfers API allows you to send money to beneficiaries through various channels, such as mobile money accounts and bank accounts. Use these endpoints to programmatically initiate and manage transfers.
All transfer-related endpoints require both standard API key authentication and additional authentication using the X-Grant header for enhanced security. Authorization: YOUR_PUBLIC_KEY
X-Grant: YOUR_PRIVATE_KEY
The Transfer Object
{
"id" : "trf_123456789" ,
"reference" : "ref_123456789" ,
"amount" : 5000 ,
"currency" : "XAF" ,
"status" : "complete" ,
"beneficiary" : "ben_123456789" ,
"channel" : "cm.mtn" ,
"description" : "Salary payment" ,
"metadata" : {},
"created_at" : "2023-01-01T12:00:00Z" ,
"completed_at" : "2023-01-01T12:05:00Z"
}
Transfer Object Properties
Unique identifier for the transfer
Your custom reference for the transfer
Amount of the transfer in the smallest currency unit
Three-letter ISO currency code
Status of the transfer: pending, processing, complete, failed, canceled
ID of the beneficiary receiving the transfer
Payment channel used for the transfer (e.g., cm.mtn, cm.orange)
Description of the transfer
Additional data attached to the transfer
Timestamp when the transfer was created
Timestamp when the transfer was completed (if applicable)
API Endpoints
List All Transfers Retrieve a list of transfers with pagination. Query Parameters Number of items per page (default: 30, max: 100)
Search by reference or beneficiary
Filter by transfer channels (comma-separated)
Start date filter (format: YYYY-MM-DD)
End date filter (format: YYYY-MM-DD)
{
"code" : 200 ,
"status" : "OK" ,
"message" : "Transfers retrieved" ,
"totals" : 50 ,
"last_page" : 2 ,
"current_page" : 1 ,
"selected" : 30 ,
"items" : [
{
"id" : "trf_123456789" ,
"reference" : "ref_123456789" ,
"amount" : 5000 ,
"currency" : "XAF" ,
"status" : "complete" ,
"beneficiary" : "ben_123456789" ,
"channel" : "cm.mtn" ,
"created_at" : "2023-01-01T12:00:00Z"
},
// More transfers...
]
}
Create a Transfer Initiate a new transfer to a beneficiary. Request Parameters Amount to transfer in the smallest currency unit
Three-letter ISO currency code (e.g., XAF)
ID of an existing beneficiary (required if beneficiary details are not provided)
Beneficiary details (required if beneficiary is not provided) Show Beneficiary Data Object
Beneficiary’s email address
Beneficiary’s phone number
Account number for bank transfers
Bank code for bank transfers
Beneficiary’s country code
Payment channel to use for the transfer
Description of the transfer
Unique reference for the transfer
Additional data to attach to the transfer
Example Requests With Existing Beneficiary
With New Beneficiary
{
"amount" : 5000 ,
"currency" : "XAF" ,
"beneficiary" : "ben_123456789" ,
"channel" : "cm.mtn" ,
"description" : "Salary payment" ,
"reference" : "salary_jan_2023"
}
{
"status" : "Accepted" ,
"message" : "Transfer initiated" ,
"code" : 201 ,
"transfer" : {
"id" : "trf_123456789" ,
"reference" : "salary_jan_2023" ,
"amount" : 5000 ,
"currency" : "XAF" ,
"status" : "pending" ,
"beneficiary" : "ben_123456789" ,
"channel" : "cm.mtn" ,
"description" : "Salary payment" ,
"created_at" : "2023-01-01T12:00:00Z"
}
}
After initiating a transfer, you should monitor its status using webhooks or by retrieving it periodically.
Retrieve a Transfer Retrieve details of a specific transfer. Path Parameters ID or reference of the transfer to retrieve
{
"status" : "Accepted" ,
"message" : "Transfer retrieved" ,
"code" : 202 ,
"transfer" : {
"id" : "trf_123456789" ,
"reference" : "salary_jan_2023" ,
"amount" : 5000 ,
"currency" : "XAF" ,
"status" : "complete" ,
"beneficiary" : "ben_123456789" ,
"channel" : "cm.mtn" ,
"description" : "Salary payment" ,
"created_at" : "2023-01-01T12:00:00Z" ,
"completed_at" : "2023-01-01T12:05:00Z"
}
}
Cancel a Transfer Cancel a pending transfer. Path Parameters ID or reference of the transfer to cancel
{
"code" : 202 ,
"status" : "Accepted" ,
"message" : "Transfer canceled successfully"
}
You can only cancel transfers that are in the pending status. Transfers that are already processing, complete, or failed cannot be canceled.
Bulk Transfers
Create a Bulk Transfer Initiate multiple transfers in a single request. Request Parameters Array of transfer objects ID of an existing beneficiary
Beneficiary details (if not using an existing beneficiary)
Three-letter ISO currency code for all transfers
Description for the bulk transfer
Example Request {
"currency" : "XAF" ,
"description" : "January 2023 Payroll" ,
"transfers" : [
{
"amount" : 5000 ,
"beneficiary" : "ben_123456789" ,
"channel" : "cm.mtn" ,
"reference" : "salary_john_jan_2023"
},
{
"amount" : 7000 ,
"beneficiary_data" : {
"name" : "Jane Doe" ,
"phone" : "+237670000001" ,
"email" : "[email protected] "
},
"channel" : "cm.orange" ,
"reference" : "salary_jane_jan_2023"
}
]
}
{
"status" : "Accepted" ,
"message" : "Bulk transfer initiated" ,
"code" : 201 ,
"bulk_transfer" : {
"id" : "btrf_123456789" ,
"description" : "January 2023 Payroll" ,
"currency" : "XAF" ,
"total_amount" : 12000 ,
"total_transfers" : 2 ,
"created_at" : "2023-01-01T12:00:00Z" ,
"transfers" : [
{
"id" : "trf_123456789" ,
"reference" : "salary_john_jan_2023" ,
"amount" : 5000 ,
"status" : "pending"
},
{
"id" : "trf_987654321" ,
"reference" : "salary_jane_jan_2023" ,
"amount" : 7000 ,
"status" : "pending"
}
]
}
}
Bulk transfers are processed asynchronously. Individual transfers may succeed or fail independently.
Retrieve a Bulk Transfer Retrieve details of a specific bulk transfer. Path Parameters ID of the bulk transfer to retrieve
{
"status" : "Accepted" ,
"message" : "Bulk transfer retrieved" ,
"code" : 202 ,
"bulk_transfer" : {
"id" : "btrf_123456789" ,
"description" : "January 2023 Payroll" ,
"currency" : "XAF" ,
"total_amount" : 12000 ,
"total_transfers" : 2 ,
"created_at" : "2023-01-01T12:00:00Z" ,
"transfers" : [
{
"id" : "trf_123456789" ,
"reference" : "salary_john_jan_2023" ,
"amount" : 5000 ,
"status" : "complete" ,
"beneficiary" : "ben_123456789" ,
"channel" : "cm.mtn" ,
"completed_at" : "2023-01-01T12:05:00Z"
},
{
"id" : "trf_987654321" ,
"reference" : "salary_jane_jan_2023" ,
"amount" : 7000 ,
"status" : "complete" ,
"beneficiary" : "ben_987654321" ,
"channel" : "cm.orange" ,
"completed_at" : "2023-01-01T12:07:00Z"
}
]
}
}
Transfer Statuses
pending Transfer has been initiated but not yet processed
processing Transfer is being processed by the payment provider
complete Transfer has been completed
failed Transfer attempt failed
canceled Transfer was canceled by the merchant
Webhooks for Transfers
To receive real-time notifications about transfer status changes, set up webhooks for the following events:
transfer.created Triggered when a new transfer is created {
"id" : "evt_123456789" ,
"type" : "transfer.created" ,
"data" : {
"id" : "trf_123456789" ,
"status" : "pending"
// Other transfer properties
}
}
transfer.complete Triggered when a transfer status changes to “complete” {
"id" : "evt_123456789" ,
"type" : "transfer.complete" ,
"data" : {
"id" : "trf_123456789" ,
"status" : "complete"
// Other transfer properties
}
}
transfer.failed Triggered when a transfer fails {
"id" : "evt_123456789" ,
"type" : "transfer.failed" ,
"data" : {
"id" : "trf_123456789" ,
"status" : "failed" ,
"failure_reason" : "Insufficient balance"
// Other transfer properties
}
}
See the Webhooks API documentation for more information on setting up and handling webhooks.
Error Handling
Invalid request parameters This typically occurs when required parameters are missing or have invalid values.
Invalid API key Check that you’re using the correct API key and that it’s properly included in the Authorization header.
Missing or invalid grant key Transfer endpoints require the X-Grant header with your private key for additional security.
Transfer not found The transfer ID or reference you provided doesn’t exist or belongs to another account.
Transfer cannot be processed This occurs when there’s a business logic error, such as insufficient balance or invalid beneficiary details.
{
"code" : 422 ,
"status" : "Unprocessable Entity" ,
"message" : "Insufficient balance to complete this transfer"
}
Solution : Add funds to your Notch Pay account before attempting the transfer.{
"code" : 422 ,
"status" : "Unprocessable Entity" ,
"message" : "Validation failed" ,
"errors" : {
"beneficiary" : [ "Beneficiary not found" ]
}
}
Solution : Ensure the beneficiary exists and is correctly specified.{
"code" : 422 ,
"status" : "Unprocessable Entity" ,
"message" : "Validation failed" ,
"errors" : {
"channel" : [ "Invalid payment channel" ]
}
}
Solution : Use one of the supported payment channels for transfers.
Best Practices
Store Transfer References Always store the transfer ID and reference in your database for future reference and reconciliation.
Verify Transfer Status Always verify the transfer status using the API before confirming to the recipient that funds have been sent.
Use Webhooks Set up webhooks for reliable transfer notifications, especially for asynchronous transfers like mobile money.
Idempotent References Use unique, idempotent references for each transfer to prevent duplicate transfers and simplify reconciliation.
Error Handling Implement proper error handling for failed transfers, including user-friendly error messages and recovery options.
Balance Management Check your account balance before initiating large transfers or bulk transfers to ensure sufficient funds.
Implementation Examples
Single Transfer
Bulk Transfer
Create a Transfer
const axios = require ( 'axios' );
async function createTransfer () {
try {
const response = await axios . post ( 'https://api.notchpay.co/transfers' , {
amount: 5000 ,
currency: 'XAF' ,
beneficiary: 'ben_123456789' ,
channel: 'cm.mtn' ,
description: 'Salary payment' ,
reference: 'salary_jan_2023'
}, {
headers: {
'Authorization' : 'YOUR_PUBLIC_KEY' ,
'X-Grant' : 'YOUR_PRIVATE_KEY' ,
'Content-Type' : 'application/json'
}
});
console . log ( 'Transfer initiated:' , response . data );
return response . data . transfer . id ;
} catch ( error ) {
console . error ( 'Error creating transfer:' , error . response ?. data || error . message );
throw error ;
}
}
Check Transfer Status
async function checkTransferStatus ( transferId ) {
try {
const response = await axios . get ( `https://api.notchpay.co/transfers/ ${ transferId } ` , {
headers: {
'Authorization' : 'YOUR_PUBLIC_KEY' ,
'X-Grant' : 'YOUR_PRIVATE_KEY'
}
});
console . log ( 'Transfer status:' , response . data . transfer . status );
return response . data . transfer ;
} catch ( error ) {
console . error ( 'Error checking transfer:' , error . response ?. data || error . message );
throw error ;
}
}
Create a Bulk Transfer
async function createBulkTransfer () {
try {
const response = await axios . post ( 'https://api.notchpay.co/transfers/bulk' , {
currency: 'XAF' ,
description: 'January 2023 Payroll' ,
transfers: [
{
amount: 5000 ,
beneficiary: 'ben_123456789' ,
channel: 'cm.mtn' ,
reference: 'salary_john_jan_2023'
},
{
amount: 7000 ,
beneficiary_data: {
name: 'Jane Doe' ,
phone: '+237670000001' ,
email: '[email protected] '
},
channel: 'cm.orange' ,
reference: 'salary_jane_jan_2023'
}
]
}, {
headers: {
'Authorization' : 'YOUR_PUBLIC_KEY' ,
'X-Grant' : 'YOUR_PRIVATE_KEY' ,
'Content-Type' : 'application/json'
}
});
console . log ( 'Bulk transfer initiated:' , response . data );
return response . data . bulk_transfer . id ;
} catch ( error ) {
console . error ( 'Error creating bulk transfer:' , error . response ?. data || error . message );
throw error ;
}
}
Check Bulk Transfer Status
async function checkBulkTransferStatus ( bulkTransferId ) {
try {
const response = await axios . get ( `https://api.notchpay.co/transfers/bulk/ ${ bulkTransferId } ` , {
headers: {
'Authorization' : 'YOUR_PUBLIC_KEY' ,
'X-Grant' : 'YOUR_PRIVATE_KEY'
}
});
console . log ( 'Bulk transfer details:' , response . data );
// Check status of individual transfers
response . data . bulk_transfer . transfers . forEach ( transfer => {
console . log ( `Transfer ${ transfer . id } : ${ transfer . status } ` );
});
return response . data . bulk_transfer ;
} catch ( error ) {
console . error ( 'Error checking bulk transfer:' , error . response ?. data || error . message );
throw error ;
}
}