Money Transfer
curl --request POST \
--url https://api.example.com/api/transfer \
--header 'API-KEY: <api-key>' \
--header 'Content-Type: <content-type>' \
--data '
{
"id": "<string>",
"sender_phone": "<string>",
"receiver_phone": "<string>",
"amount": "<string>",
"service": "<string>",
"receiver_country": "<string>",
"receiver_currency": "<string>",
"attribute": [
{}
]
}
'import requests
url = "https://api.example.com/api/transfer"
payload = {
"id": "<string>",
"sender_phone": "<string>",
"receiver_phone": "<string>",
"amount": "<string>",
"service": "<string>",
"receiver_country": "<string>",
"receiver_currency": "<string>",
"attribute": [{}]
}
headers = {
"API-KEY": "<api-key>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'API-KEY': '<api-key>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
id: '<string>',
sender_phone: '<string>',
receiver_phone: '<string>',
amount: '<string>',
service: '<string>',
receiver_country: '<string>',
receiver_currency: '<string>',
attribute: [{}]
})
};
fetch('https://api.example.com/api/transfer', 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.example.com/api/transfer",
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([
'id' => '<string>',
'sender_phone' => '<string>',
'receiver_phone' => '<string>',
'amount' => '<string>',
'service' => '<string>',
'receiver_country' => '<string>',
'receiver_currency' => '<string>',
'attribute' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"API-KEY: <api-key>",
"Content-Type: <content-type>"
],
]);
$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.example.com/api/transfer"
payload := strings.NewReader("{\n \"id\": \"<string>\",\n \"sender_phone\": \"<string>\",\n \"receiver_phone\": \"<string>\",\n \"amount\": \"<string>\",\n \"service\": \"<string>\",\n \"receiver_country\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"attribute\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("API-KEY", "<api-key>")
req.Header.Add("Content-Type", "<content-type>")
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.example.com/api/transfer")
.header("API-KEY", "<api-key>")
.header("Content-Type", "<content-type>")
.body("{\n \"id\": \"<string>\",\n \"sender_phone\": \"<string>\",\n \"receiver_phone\": \"<string>\",\n \"amount\": \"<string>\",\n \"service\": \"<string>\",\n \"receiver_country\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"attribute\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/transfer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["API-KEY"] = '<api-key>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"id\": \"<string>\",\n \"sender_phone\": \"<string>\",\n \"receiver_phone\": \"<string>\",\n \"amount\": \"<string>\",\n \"service\": \"<string>\",\n \"receiver_country\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"attribute\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"payment_response": {
"payment_id": null,
"state": "-2",
"substate": "0",
"code": "0",
"id": "123456789"
},
"error": "",
"success": true
}
{
"error": {
"message": "Insufficient funds in merchant account",
"code": "insufficient_funds"
},
"success": "false"
}
{
"error": {
"message": "Invalid phone number format",
"code": "invalid_phone_number"
},
"success": "false"
}
Endpoints
Money Transfer
Execute a money transfer to any phone number
POST
/
api
/
transfer
Money Transfer
curl --request POST \
--url https://api.example.com/api/transfer \
--header 'API-KEY: <api-key>' \
--header 'Content-Type: <content-type>' \
--data '
{
"id": "<string>",
"sender_phone": "<string>",
"receiver_phone": "<string>",
"amount": "<string>",
"service": "<string>",
"receiver_country": "<string>",
"receiver_currency": "<string>",
"attribute": [
{}
]
}
'import requests
url = "https://api.example.com/api/transfer"
payload = {
"id": "<string>",
"sender_phone": "<string>",
"receiver_phone": "<string>",
"amount": "<string>",
"service": "<string>",
"receiver_country": "<string>",
"receiver_currency": "<string>",
"attribute": [{}]
}
headers = {
"API-KEY": "<api-key>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'API-KEY': '<api-key>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
id: '<string>',
sender_phone: '<string>',
receiver_phone: '<string>',
amount: '<string>',
service: '<string>',
receiver_country: '<string>',
receiver_currency: '<string>',
attribute: [{}]
})
};
fetch('https://api.example.com/api/transfer', 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.example.com/api/transfer",
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([
'id' => '<string>',
'sender_phone' => '<string>',
'receiver_phone' => '<string>',
'amount' => '<string>',
'service' => '<string>',
'receiver_country' => '<string>',
'receiver_currency' => '<string>',
'attribute' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"API-KEY: <api-key>",
"Content-Type: <content-type>"
],
]);
$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.example.com/api/transfer"
payload := strings.NewReader("{\n \"id\": \"<string>\",\n \"sender_phone\": \"<string>\",\n \"receiver_phone\": \"<string>\",\n \"amount\": \"<string>\",\n \"service\": \"<string>\",\n \"receiver_country\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"attribute\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("API-KEY", "<api-key>")
req.Header.Add("Content-Type", "<content-type>")
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.example.com/api/transfer")
.header("API-KEY", "<api-key>")
.header("Content-Type", "<content-type>")
.body("{\n \"id\": \"<string>\",\n \"sender_phone\": \"<string>\",\n \"receiver_phone\": \"<string>\",\n \"amount\": \"<string>\",\n \"service\": \"<string>\",\n \"receiver_country\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"attribute\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/transfer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["API-KEY"] = '<api-key>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"id\": \"<string>\",\n \"sender_phone\": \"<string>\",\n \"receiver_phone\": \"<string>\",\n \"amount\": \"<string>\",\n \"service\": \"<string>\",\n \"receiver_country\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"attribute\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"payment_response": {
"payment_id": null,
"state": "-2",
"substate": "0",
"code": "0",
"id": "123456789"
},
"error": "",
"success": true
}
{
"error": {
"message": "Insufficient funds in merchant account",
"code": "insufficient_funds"
},
"success": "false"
}
{
"error": {
"message": "Invalid phone number format",
"code": "invalid_phone_number"
},
"success": "false"
}
Overview
Execute a money transfer from your merchant account to any phone number in supported countries. This endpoint processes the actual transfer and debits your account.Important: Always call Check Transfer before executing a transfer to validate parameters and check receiver status.
Endpoint
POST /api/transfer
Authentication
string
required
Your CashQ API Key for authentication
string
required
Must be
application/jsonRequest Body
The request body parameters are identical to Check Transfer.string
required
Unique numeric identifier for this transfer. Should match the ID used in Check Transfer. Must be numeric only.
string
required
Sender’s phone number in E.164 format (e.g.,
"+15615019469")string
required
Receiver’s phone number in E.164 format (e.g.,
"+201234567890")string
required
Transfer amount in dollars (e.g.,
"5.0" for $5.00)string
required
ID of corridor (e.g.,
"1271" for EGP). Payment attributes depend on the corridor and will be provided for the requested corridor upon request.string
required
Country code of receiver (e.g.,
"MX" for Mexico, "EG" for Egypt).string
required
Currency code for the receiver (e.g.,
"MXN" for Mexican Peso, "EGP" for Egyptian Pound)array
required
Array of corridor-specific payment attributes. Required attributes vary by corridor and include receiver details, bank information, address, and identification. Contact support for specific corridor requirements.
Show Attribute structure
Show Attribute structure
Each attribute object contains:
name(string): Attribute namevalue(string): Attribute value
receivedAmount- Amount in receiver’s currency (e.g., amount in EGP)receiverName- Full name of receiverreceiverFirstName- Receiver’s first namereceiverLastName- Receiver’s last namereceiverAddressStreet- Street addressreceiverAddressCity- CityreceiverAddressState- State/RegionreceiverAddressCountry- Country code (e.g., “EG”)receiverAccType- Account type (e.g., “1” for bank account)receiverIssuerCode- Bank issuer codereceiverAccountNumber- Bank account numberreceiverBankBranchCode- Bank branch code (optional, if applicable)receiverBankName- Bank namereceiverIdType- ID type (“2” for International Passport, “3” for Identification ID)receiverIdNumber- Identification number
Important: Without this attribute, the transaction will be created but will wait for automated/manual reconciliation checking, which may cause delays.
approvelyId AttributeIf you’re using the Payout API with our Payin API, you must include the approvelyId attribute to link the payout with the payin transaction:{
"name": "approvelyId",
"value": "46364493"
}
Request Example
curl -X POST 'https://api.cashqbot.com/api/transfer' \
-H 'API-KEY: your_api_key_here' \
-H 'Content-Type: application/json' \
-d '{
"id": "123456789",
"sender_phone": "+15551234567",
"receiver_phone": "+525551234568",
"amount": "5.0",
"service": "1234",
"receiver_country": "MX",
"receiver_currency": "MXN",
"attribute": []
}'
const transferData = {
id: '123456789',
sender_phone: '+15551234567',
receiver_phone: '+525551234568',
amount: '5.0',
service: '1234',
receiver_country: 'MX',
receiver_currency: 'MXN',
attribute: []
};
const response = await fetch('https://api.cashqbot.com/api/transfer', {
method: 'POST',
headers: {
'API-KEY': 'your_api_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify(transferData)
});
const data = await response.json();
console.log(data);
import requests
import json
transfer_data = {
'id': '123456789',
'sender_phone': '+15551234567',
'receiver_phone': '+525551234568',
'amount': '5.0',
'service': '1234',
'receiver_country': 'MX',
'receiver_currency': 'MXN',
'attribute': []
}
response = requests.post(
'https://api.cashqbot.com/api/transfer',
headers={
'API-KEY': 'your_api_key_here',
'Content-Type': 'application/json'
},
json=transfer_data
)
data = response.json()
print(data)
<?php
$transferData = [
'id' => '123456789',
'sender_phone' => '+15551234567',
'receiver_phone' => '+525551234568',
'amount' => '5.0',
'service' => '1234',
'receiver_country' => 'MX',
'receiver_currency' => 'MXN',
'attribute' => []
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.cashqbot.com/api/transfer');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'API-KEY: your_api_key_here',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($transferData));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);
?>
Response
boolean
required
Indicates if the transfer was initiated successfully
string
Error message if transfer failed, empty string if successful
object
Response Examples
{
"payment_response": {
"payment_id": null,
"state": "-2",
"substate": "0",
"code": "0",
"id": "123456789"
},
"error": "",
"success": true
}
{
"error": {
"message": "Insufficient funds in merchant account",
"code": "insufficient_funds"
},
"success": "false"
}
{
"error": {
"message": "Invalid phone number format",
"code": "invalid_phone_number"
},
"success": "false"
}
Complete Transfer Flow
Follow this recommended flow for executing transfers:1
Check balance
Verify you have sufficient funds using Get Balance
const balance = await getBalance();
if (balance.balance + balance.overdraft < amountInCents) {
throw new Error('Insufficient funds');
}
2
Check KYC
Verify receiver’s KYC status using Check KYC
const kyc = await checkKYC(receiverPhone);
if (parseFloat(kyc.money_limit) < amount) {
throw new Error('Amount exceeds receiver limit');
}
3
Validate transfer
Call Check Transfer to validate parameters
const validation = await checkTransfer(transferData);
if (!validation.success) {
throw new Error('Validation failed');
}
4
Execute transfer
Call this endpoint to execute the transfer
const result = await executeTransfer(transferData);
5
Monitor status
Use Check Status to monitor transfer completion
const status = await pollTransferStatus(transferId);
Transfer States
After initiating a transfer, monitor its status:| State | Description | Action |
|---|---|---|
| 0 | New | Transfer created, processing starting |
| 40 | Processing | Transfer in progress |
| 60 | Success | Transfer completed successfully |
| 80 | Error | Transfer failed |
| -2 | Not Found | Transfer ID not found |
See the complete Status Codes Reference for all possible states.
Error Responses
| Error Code | Description | Solution |
|---|---|---|
authentication_error | Invalid or missing API key | Verify your API key |
insufficient_funds | Not enough balance | Add funds or reduce amount |
invalid_phone_number | Phone number format incorrect | Use E.164 format without + |
invalid_amount | Amount is invalid | Check amount is positive and formatted correctly |
kyc_not_verified | Receiver KYC limits exceeded | Reduce amount or ask receiver to verify |
duplicate_transfer | Transfer ID already used | Use a unique transfer ID |
internal_server_error | Server error occurred | Retry the request |
Best Practices
Always validate first
Always validate first
Call Check Transfer before executing to catch errors early and check receiver status.
Use unique transfer IDs
Use unique transfer IDs
Generate unique IDs for each transfer. Reusing IDs may cause duplicate transfer errors.
Check balance before transfer
Check balance before transfer
Verify sufficient funds to avoid insufficient balance errors.
Monitor transfer status
Monitor transfer status
Poll the status endpoint to track transfer completion and handle any issues.
Handle payment invitations
Handle payment invitations
Inform users when sending to new receivers about the 6-hour expiration window.
Implement idempotency
Implement idempotency
Store transfer IDs and results to prevent duplicate transfers if requests are retried.
Log all transfers
Log all transfers
Keep detailed logs of all transfer attempts for debugging and reconciliation.
Related Endpoints
Check Transfer
Validate transfer before execution
Check Status
Monitor transfer status after execution
Get Balance
Check available funds before transfer
Check KYC
Verify receiver’s limits before transfer
