curl -X POST "https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate" \
--header "Authorization: Bearer your-jwt-token" \
--header "Content-Type: application/json" \
--header "Accept-Language: en" \
--header "X-Idempotency-Key: your-idempotency-key" \
-d '{
"merchantAccountNumber": 12345678,
"connectorId": 550044,
"payerAccountNumber": "0999000000",
"sourceReferenceNumber": "OKPG90WOIJD98JKSJKH",
"transactionDescription": "Groceries Order Payment",
"transactionAmount": 100.00,
"capturedBy": "john.doe@onekhusa.com"
}'import requests
url = "https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate"
payload = {
"merchantAccountNumber": 12345678,
"connectorId": 550044,
"payerAccountNumber": "0999000000",
"sourceReferenceNumber": "OKPG90WOIJD98JKSJKH",
"transactionDescription": "Groceries Order Payment",
"transactionAmount": 100,
"capturedBy": "john.doe@onekhusa.com"
}
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({
merchantAccountNumber: 12345678,
connectorId: 550044,
payerAccountNumber: '0999000000',
sourceReferenceNumber: 'OKPG90WOIJD98JKSJKH',
transactionDescription: 'Groceries Order Payment',
transactionAmount: 100,
capturedBy: 'john.doe@onekhusa.com'
})
};
fetch('https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate', 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.onekhusa.com/sandbox/v1/collections/push/direct/initiate",
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([
'merchantAccountNumber' => 12345678,
'connectorId' => 550044,
'payerAccountNumber' => '0999000000',
'sourceReferenceNumber' => 'OKPG90WOIJD98JKSJKH',
'transactionDescription' => 'Groceries Order Payment',
'transactionAmount' => 100,
'capturedBy' => 'john.doe@onekhusa.com'
]),
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.onekhusa.com/sandbox/v1/collections/push/direct/initiate"
payload := strings.NewReader("{\n \"merchantAccountNumber\": 12345678,\n \"connectorId\": 550044,\n \"payerAccountNumber\": \"0999000000\",\n \"sourceReferenceNumber\": \"OKPG90WOIJD98JKSJKH\",\n \"transactionDescription\": \"Groceries Order Payment\",\n \"transactionAmount\": 100,\n \"capturedBy\": \"john.doe@onekhusa.com\"\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.onekhusa.com/sandbox/v1/collections/push/direct/initiate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"merchantAccountNumber\": 12345678,\n \"connectorId\": 550044,\n \"payerAccountNumber\": \"0999000000\",\n \"sourceReferenceNumber\": \"OKPG90WOIJD98JKSJKH\",\n \"transactionDescription\": \"Groceries Order Payment\",\n \"transactionAmount\": 100,\n \"capturedBy\": \"john.doe@onekhusa.com\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate")
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 \"merchantAccountNumber\": 12345678,\n \"connectorId\": 550044,\n \"payerAccountNumber\": \"0999000000\",\n \"sourceReferenceNumber\": \"OKPG90WOIJD98JKSJKH\",\n \"transactionDescription\": \"Groceries Order Payment\",\n \"transactionAmount\": 100,\n \"capturedBy\": \"john.doe@onekhusa.com\"\n}"
response = http.request(request)
puts response.read_body{
"merchantAccountNumber": 12345678,
"sourceReferenceNumber": "OKPG90WOIJD98JKSJKH",
"responseCode": "I100",
"feeRuleCode": "CC",
"transactionAmount": 100,
"totalCharges": 2.5,
"amountToPay": 102.5
}Push Payment API
The Direct Push Payment API allows merchants to initiate instant USSD payment prompts to customer Mobile Money (MoMo) wallets. This endpoint acts as a synchronous trigger that initiates the collection payment flow, with final transaction status communicated asynchronously via webhooks.
curl -X POST "https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate" \
--header "Authorization: Bearer your-jwt-token" \
--header "Content-Type: application/json" \
--header "Accept-Language: en" \
--header "X-Idempotency-Key: your-idempotency-key" \
-d '{
"merchantAccountNumber": 12345678,
"connectorId": 550044,
"payerAccountNumber": "0999000000",
"sourceReferenceNumber": "OKPG90WOIJD98JKSJKH",
"transactionDescription": "Groceries Order Payment",
"transactionAmount": 100.00,
"capturedBy": "john.doe@onekhusa.com"
}'import requests
url = "https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate"
payload = {
"merchantAccountNumber": 12345678,
"connectorId": 550044,
"payerAccountNumber": "0999000000",
"sourceReferenceNumber": "OKPG90WOIJD98JKSJKH",
"transactionDescription": "Groceries Order Payment",
"transactionAmount": 100,
"capturedBy": "john.doe@onekhusa.com"
}
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({
merchantAccountNumber: 12345678,
connectorId: 550044,
payerAccountNumber: '0999000000',
sourceReferenceNumber: 'OKPG90WOIJD98JKSJKH',
transactionDescription: 'Groceries Order Payment',
transactionAmount: 100,
capturedBy: 'john.doe@onekhusa.com'
})
};
fetch('https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate', 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.onekhusa.com/sandbox/v1/collections/push/direct/initiate",
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([
'merchantAccountNumber' => 12345678,
'connectorId' => 550044,
'payerAccountNumber' => '0999000000',
'sourceReferenceNumber' => 'OKPG90WOIJD98JKSJKH',
'transactionDescription' => 'Groceries Order Payment',
'transactionAmount' => 100,
'capturedBy' => 'john.doe@onekhusa.com'
]),
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.onekhusa.com/sandbox/v1/collections/push/direct/initiate"
payload := strings.NewReader("{\n \"merchantAccountNumber\": 12345678,\n \"connectorId\": 550044,\n \"payerAccountNumber\": \"0999000000\",\n \"sourceReferenceNumber\": \"OKPG90WOIJD98JKSJKH\",\n \"transactionDescription\": \"Groceries Order Payment\",\n \"transactionAmount\": 100,\n \"capturedBy\": \"john.doe@onekhusa.com\"\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.onekhusa.com/sandbox/v1/collections/push/direct/initiate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"merchantAccountNumber\": 12345678,\n \"connectorId\": 550044,\n \"payerAccountNumber\": \"0999000000\",\n \"sourceReferenceNumber\": \"OKPG90WOIJD98JKSJKH\",\n \"transactionDescription\": \"Groceries Order Payment\",\n \"transactionAmount\": 100,\n \"capturedBy\": \"john.doe@onekhusa.com\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.onekhusa.com/sandbox/v1/collections/push/direct/initiate")
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 \"merchantAccountNumber\": 12345678,\n \"connectorId\": 550044,\n \"payerAccountNumber\": \"0999000000\",\n \"sourceReferenceNumber\": \"OKPG90WOIJD98JKSJKH\",\n \"transactionDescription\": \"Groceries Order Payment\",\n \"transactionAmount\": 100,\n \"capturedBy\": \"john.doe@onekhusa.com\"\n}"
response = http.request(request)
puts response.read_body{
"merchantAccountNumber": 12345678,
"sourceReferenceNumber": "OKPG90WOIJD98JKSJKH",
"responseCode": "I100",
"feeRuleCode": "CC",
"transactionAmount": 100,
"totalCharges": 2.5,
"amountToPay": 102.5
}Webhook Event Notifications
Because MoMo (Mobile Money) payment authorization relies on user PIN entry on their handset, final transaction outcomes are delivered asynchronously through OneKhusa webhooks. Register an HTTP POST endpoint to listen for the following three events:-
pushpayment.success: Triggered when the customer enters their PIN and the payment successfully settles.Refer to the Push Payment Webhook for the event headers and JSON payload. -
pushpayment.failed: Triggered if the customer cancels the prompt, enters an incorrect PIN, times out, or has insufficient funds etc.Refer to the Push Payment Webhook for the event headers and JSON payload. -
pushpayment.reversed: Triggered if a previously successful payment is reversed by the MoMo operator (e.g., due to duplicate debit reconciliation).Refer to the Push Payment Webhook for the event headers and JSON payload.
Implementation Guidelines
-
Idempotency: Ensure
sourceReferenceNumberis unique per payment request to prevent accidental duplicate prompts. -
Synchronous vs Asynchronous handling: Treat the
/collections/push/direct/initiateresponse as acknowledgment of prompt delivery only. Do not fulfill orders or grant service access until receiving apushpayment.successwebhook. -
Webhook Verification: Verify incoming webhook signatures using the
X-OneKhusa-Webhook-Signatureheader to ensure authenticity. - Simulate Payment Authorization: Once the payment is initiated in sandbox environment, login to OneKhusa merchant portal, navigate to Test Your Integration -> Simulate Push Payment page. Perform the actions expected from MoMo providers to hard-proof your integrations.
Authorizations
Bearer authentication header of the form Bearer Token, Where accessToken is the access token used to authenticate the request.
Body
Your unique OneKhusa merchant account number.
12345678
Identifier for the targeted Mobile Money connector/provider, for example TNM Mpamba or Airtel Money. Use the Get All Connectors endpoint to look up the connector identifier.
550044
Mobile Money phone number of the payer (MSISDN).
"0999000000"
Unique reference number generated by your merchant system. Keep it unique per payment request to prevent accidental duplicate prompts.
5 - 25"OKPG90WOIJD98JKSJKH"
Narrative or memo for the transaction shown to the customer.
"Groceries Order Payment"
Payment amount requested.
100
User email initiating the API request.
"john.doe@onekhusa.com"
Response
The request was validated and the USSD prompt was dispatched to the Mobile Money provider. This response does not confirm payment completion, use the push payment webhooks to receive the final transaction status.
Associated merchant account number.
12345678
The unique reference number passed in the request.
"OKPG90WOIJD98JKSJKH"
Internal status code, where I100 indicates successful push initiation.
"I100"
Applied fee calculation structure code, i.e. CC - Charge To Customer and CM - Charge To Merchant.
"CC"
Original transaction amount requested.
100
Processing charges and gateway fees calculated for this payment request.
2.5
Total amount to be debited/collected from the customer.
102.5