Guides & Recipes
Collect Money Cross-Border
This guide walks you through pulling funds from a sender in their local currency via bank transfer or mobile money.
Overview
1. Enroll Customer POST /v1/customer/enroll
2. Submit KYC POST /v1/customer/{uuid}/kyc
3. Await KYC Approval GET /v1/customer/{uuid}/kyc
4. Get Channels GET /v1/crossborder/channels?ramptype=deposit
5. Get Networks GET /v1/crossborder/networks
6. Initiate Collection POST /v1/crossborder/global-collection
7. Confirm Status Webhook: crossborder.collection.successStep 1 — Enroll the Customer (Sender)
const axios = require("axios");
const { data: enrollment } = await axios.post(
"https://sandbox.hitchpay.ng/v1/customer/enroll",
{
customerid: "SENDER_001",
email: "[email protected]",
phone: "254722123456",
firstname: "Amara",
lastname: "Okafor",
dob: "15-06-1988",
nationality: "KE",
image: "https://storage.yourapp.com/profile.jpg",
address: {
house_no: 3, street: "Moi Avenue",
city: "Nairobi", state: "Nairobi",
postal_code: "00100", country: "KE"
}
},
{ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" } }
);
const customerUuid = enrollment.data.uuid;<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/customer/enroll",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
"customerid" => "SENDER_001", "email" => "[email protected]",
"phone" => "254722123456", "firstname" => "Amara", "lastname" => "Okafor",
"dob" => "15-06-1988", "nationality" => "KE",
"image" => "https://storage.yourapp.com/profile.jpg",
"address" => [
"house_no" => 3, "street" => "Moi Avenue",
"city" => "Nairobi", "state" => "Nairobi",
"postal_code" => "00100", "country" => "KE"
]
]),
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$accessToken}", "Content-Type: application/json"]
]);
$enrollment = json_decode(curl_exec($ch), true);
curl_close($ch);
$customerUuid = $enrollment["data"]["uuid"];import requests
enrollment = requests.post(
"https://sandbox.hitchpay.ng/v1/customer/enroll",
json={
"customerid": "SENDER_001", "email": "[email protected]",
"phone": "254722123456", "firstname": "Amara", "lastname": "Okafor",
"dob": "15-06-1988", "nationality": "KE",
"image": "https://storage.yourapp.com/profile.jpg",
"address": {
"house_no": 3, "street": "Moi Avenue",
"city": "Nairobi", "state": "Nairobi",
"postal_code": "00100", "country": "KE"
}
},
headers={"Authorization": f"Bearer {access_token}"}
).json()
customer_uuid = enrollment["data"]["uuid"]Step 2 & 3 — Submit KYC and Await Approval
Submit the sender's ID documents and wait until overall_kyc_status is approved before proceeding.
See Send Money Internationally for the full KYC polling pattern.
Step 4 — Get Deposit Channels
Fetch channels using ramptype=deposit (for collections).
const { data: channels } = await axios.get(
"https://sandbox.hitchpay.ng/v1/crossborder/channels",
{ params: { country_code: "KE", ramptype: "deposit" },
headers: { Authorization: `Bearer ${accessToken}` } }
);
// Pick bank or momo channel
const bankChannel = channels.data.find(c => c.value === "bank");
const momoChannel = channels.data.find(c => c.value === "momo");<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/crossborder/channels?country_code=KE&ramptype=deposit",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$accessToken}"]
]);
$channels = json_decode(curl_exec($ch), true)["data"];
curl_close($ch);channels = requests.get(
"https://sandbox.hitchpay.ng/v1/crossborder/channels",
params={"country_code": "KE", "ramptype": "deposit"},
headers={"Authorization": f"Bearer {access_token}"}
).json()["data"]
bank_channel = next(c for c in channels if c["value"] == "bank")
momo_channel = next(c for c in channels if c["value"] == "momo")Step 5 — Get Networks
const { data: networks } = await axios.get(
"https://sandbox.hitchpay.ng/v1/crossborder/networks",
{ params: { country_code: "KE", channel: "momo" },
headers: { Authorization: `Bearer ${accessToken}` } }
);
const networkId = networks.data.find(n => n.name === "M-PESA").network_id;<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/crossborder/networks?country_code=KE&channel=momo",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$accessToken}"]
]);
$networks = json_decode(curl_exec($ch), true)["data"];
curl_close($ch);
$networkId = $networks[0]["network_id"];networks = requests.get(
"https://sandbox.hitchpay.ng/v1/crossborder/networks",
params={"country_code": "KE", "channel": "momo"},
headers={"Authorization": f"Bearer {access_token}"}
).json()["data"]
network_id = next(n for n in networks if n["name"] == "M-PESA")["network_id"]Step 6 — Initiate the Collection
const { data: collection } = await axios.post(
"https://sandbox.hitchpay.ng/v1/crossborder/global-collection",
{
customer_uuid: customerUuid,
amount: 5000,
currency: "KES",
channel_id: momoChannel.channelid,
account_number: "254722123456",
network_id: networkId,
reason: "Service payment",
reference: "REF_COLLECT_001",
dial_code: "+254",
account_type: "momo",
country_code: "KE"
},
{ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" } }
);
console.log("Collection initiated:", collection.data.reference);
// For momo: sender receives a payment prompt on their phone automatically<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/crossborder/global-collection",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
"customer_uuid" => $customerUuid,
"amount" => 5000,
"currency" => "KES",
"channel_id" => $momoChannelId,
"account_number" => "254722123456",
"network_id" => $networkId,
"reason" => "Service payment",
"reference" => "REF_COLLECT_001",
"dial_code" => "+254",
"account_type" => "momo",
"country_code" => "KE"
]),
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$accessToken}", "Content-Type: application/json"]
]);
$collection = json_decode(curl_exec($ch), true);
curl_close($ch);collection = requests.post(
"https://sandbox.hitchpay.ng/v1/crossborder/global-collection",
json={
"customer_uuid": customer_uuid,
"amount": 5000,
"currency": "KES",
"channel_id": momo_channel["channelid"],
"account_number": "254722123456",
"network_id": network_id,
"reason": "Service payment",
"reference": "REF_COLLECT_001",
"dial_code": "+254",
"account_type": "momo",
"country_code": "KE"
},
headers={"Authorization": f"Bearer {access_token}"}
).json()
print("Collection initiated:", collection["data"]["reference"])Step 7 — Confirm via Webhook
Listen for the crossborder.collection.success or crossborder.collection.failed event on your webhook endpoint.
{
"event": "crossborder.collection.success",
"data": {
"reference": "HTCCBEF4EC275285",
"status": "successful",
"amount": 5000,
"currency": "KES",
"account_type": "momo",
"customer_uuid": "dda04ec3-3774-4750-ae7b-0c070e8d084b"
},
"sent_at": "2026-03-16T12:30:00.000Z"
}Summary
| Step | Action | Endpoint |
|---|---|---|
| 1 | Enroll sender | POST /v1/customer/enroll |
| 2–3 | Submit & await KYC | POST + GET /v1/customer/{uuid}/kyc |
| 4 | Get deposit channels | GET /v1/crossborder/channels?ramptype=deposit |
| 5 | Get networks | GET /v1/crossborder/networks |
| 6 | Initiate collection | POST /v1/crossborder/global-collection |
| 7 | Confirm outcome | crossborder.collection.success webhook |
Questions? Email [email protected]. Also on GitBook.