Hello. I am receiving the following response when attempting to make an HTTP request: The requested URL was rejected. Please consult with your administrator. Your support ID is: 8780736962620738016.
The error happens exactly on the line below:
let requestToPay = nk.httpRequest(requestUrl, "post", requestHeaders, JSON.stringify(requestBody));
Please refer to the rest of my code below and help:
// Define MTN MoMo API Configuration
const MOMO_API_BASE_URL = "https://proxy.momoapi.mtn.com"; // Use sandbox for testing
const MOMO_PRIMARY_KEY = "cc442xxxxxxxxxxxxxxxxx4e"; // Replace with your actual key
const MOMO_API_USER_ID = "bxxxxxxxxxxxxxxxxxxda92"; // Replace with your generated API User ID
const MOMO_API_KEY = "6f3xxxxxxxxxxxxxxxxxxxxxxxxaa"; // Replace with your generated API Key
const MOMO_CALLBACK_HOST = "https://webhook.site/xxxxxxxxxxxxxxxxxxxxx";
const CURRENCY = "SZL";
const ENVIRONMENT = "mtnswaziland";
// Function to get an access token from the MTN MoMo API
let getMomoAccessToken = function (nk: nkruntime.Nakama, logger: nkruntime.Logger): string | null {
const url = `${MOMO_API_BASE_URL}/collection/token/`;
const auth = "Basic " + nk.base64Encode(`${MOMO_API_USER_ID}:${MOMO_API_KEY}`);
logger.info(url);
try {
const response = nk.httpRequest(
url,
"post",
{
"Authorization": auth,
"Ocp-Apim-Subscription-Key": MOMO_PRIMARY_KEY,
},
//null
);
const body = JSON.parse(response.body);
return body.access_token;
} catch (error) {
logger.error("Error getting MoMo access token: %v", error);
return null;
}
}
// Modified rpcProcessDeposit function with server-side polling
let rpcProcessDeposit: nkruntime.RpcFunction = function (ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama, payload: string): string {
if (!ctx.userId) {
return JSON.stringify({ success: false, error: "No user ID in context" });
}
try {
const request = JSON.parse(payload);
const amount = Number(request.amount);
const phoneNumber = request.phoneNumber || '';
// --- (keep your existing validation logic) ---
if (isNaN(amount) || amount <= 0) {
return JSON.stringify({ success: false, error: "Invalid deposit amount" });
}
const minDeposit = 10;
if (amount < minDeposit) {
return JSON.stringify({
success: false,
error: `Minimum deposit amount is ${minDeposit} SZL`
});
}
if (phoneNumber && !isValidPhoneNumber(phoneNumber)) {
return JSON.stringify({
success: false,
error: "Invalid phone number. Must be 8 digits starting with 76 or 78"
});
}
// --- (end of existing validation) ---
// 1. Get Access Token
const accessToken = getMomoAccessToken(nk, logger);
if (!accessToken) {
return JSON.stringify({ success: false, error: "Could not authenticate with payment provider." });
}
logger.info(accessToken);
logger.info("Got Token and displayed it");
// 2. Initiate the payment request
const externalId = nk.uuidv4();
const requestUrl = `${MOMO_API_BASE_URL}/collection/v1_0/requesttopay`;
const requestBody = {
"amount": amount.toString(),
"currency": CURRENCY,
"externalId": externalId,
"payer": { "partyIdType": "MSISDN", "partyId": `268${phoneNumber}` },
"payerMessage": "Deposit for Crazy Eights",
"payeeNote": "Thanks for your deposit!"
};
const requestHeaders = {
"Authorization": `Bearer ${accessToken}`,
"X-Reference-Id": externalId,
"X-Target-Environment": ENVIRONMENT,
"X-Callback-Url": MOMO_CALLBACK_HOST,
"Ocp-Apim-Subscription-Key": MOMO_PRIMARY_KEY,
"Content-Type": "application/json",
"User-Agent": "Nakama",
};
logger.info("Here");
let requestToPay = nk.httpRequest(requestUrl, "post", requestHeaders, JSON.stringify(requestBody));
logger.info(requestToPay.code.toString());
logger.info(requestToPay.body);
// 3. Poll for the transaction status
const maxRetries = 30;
let finalStatus = "PENDING";
for (let i = 0; i < maxRetries; i++) {
// Wait for 2 seconds before checking the status
const sleep = (ms: number) => new Promise(res => setTimeout(res, ms));
sleep(2000);
logger.info("Here1");
const statusUrl = `${MOMO_API_BASE_URL}/collection/v1_0/requesttopay/${externalId}`;
logger.info("Here2");
const statusHeaders = {
"Authorization": `Bearer ${accessToken}`,
"X-Target-Environment": ENVIRONMENT,
"Ocp-Apim-Subscription-Key": MOMO_PRIMARY_KEY,
};
const response = nk.httpRequest(statusUrl, "get", statusHeaders/*, null*/);
const body = JSON.parse(response.body);
finalStatus = body.status;
if (finalStatus !== "PENDING") {
break;
}
}
// 4. Process the final status
if (finalStatus === "SUCCESSFUL") {
const changeset = { "szl": amount };
const metadata = { "type": "deposit", "externalId": externalId };
nk.walletUpdate(ctx.userId, changeset, metadata, true);
const account = nk.accountGetId(ctx.userId);
const updatedBalance = account.wallet["szl"] || 0;
return JSON.stringify({ success: true, balance: updatedBalance });
} else {
return JSON.stringify({ success: false, error: "Transaction failed or timed out." });
}
} catch (error) {
logger.error("Error processing deposit: %v", error);
return JSON.stringify({ success: false, error: String(error) });
}
}