Skip to content
HitchPay API Docs

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.success

Step 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.