API Communication Gateway
This chapter deep-dives into the asynchronous networking architecture of the `sendSms` gateway wrapper. It covers endpoint correction routines, authorization token formatting, response stream isolation, and defensive JSON parsing to guard against upstream proxy breakdowns.
The core execution engine of the SMS module is the sendSms function. This function handles environment inspection, input validation, HTTP request modeling, and error mitigation. It communicates directly with BongaTech’s upstream infrastructure securely via Node’s native fetch subsystem.
Self-Healing Endpoint Selection
To prevent deprecation lockouts, the module intercepts the target gateway URL at runtime. If the configured BONGATECH_API_URL variable references an older domain variant (e.g., matching api.bongatech.co.ke), the engine self-corrects the path to point directly to the stable REST version:
typescriptlet apiUrl = process.env.BONGATECH_API_URL || '[https://bulk.bongatech.co.ke/api/v1/send-sms](https://bulk.bongatech.co.ke/api/v1/send-sms)';
if (apiUrl.includes('api.bongatech.co.ke/sms/v1/send') || apiUrl.includes('api.bongatech.co.ke')) {
apiUrl = '[https://bulk.bongatech.co.ke/api/v1/send-sms](https://bulk.bongatech.co.ke/api/v1/send-sms)';
}
HTTP Payload Structure & Headers
All communications are dispatched via an encrypted POST request. The authorization token is injected securely into the HTTP header space using the standard Bearer scheme.
Wire Protocol Representation
httpPOST /api/v1/send-sms HTTP/1.1
Host: bulk.bongatech.co.ke
Content-Type: application/json
Accept: application/json
Authorization: Bearer bt_sk_live_9a7d32e5b1f4c6e80d2a1b3c4d5e6f
{
"phone": "254712345678",
"sender": "GEOHACK",
"message": "Dear Customer,\nWe have received your payment..."
}
Fault-Tolerant JSON Parsing & Stream Isolation
A common failure mode in production integrations occurs when the upstream API gateway encounters an internal crash or proxy timeout. When this happens, load balancers like Cloudflare or Nginx throw an HTML error page (e.g., 502 Bad Gateway or 504 Gateway Timeout).
Calling standard response.json() directly on such responses throws an uncaught syntax exception, crashing the local process thread.
To eliminate this vulnerability, the system isolates the stream using a text-first lookahead approach:
await response.text(): Captures the raw buffer as a plain string string regardless of what the server returned.try / catchGuard: Attempts to parse the string buffer into a JSON object inside a micro-try block.- Graceful Fallback: If parsing fails because of HTML text presence, it suppresses the structural crash, logs the text snippet natively for developers, and wraps the issue into a standard error signature.
Resilience Logic Flow
typescriptconst responseText = await response.text();
let data: any = {};
try {
data = JSON.parse(responseText);
} catch {
console.error('[BongaTech SMS Error] API returned non-JSON response:', {
status: response.status,
responseText,
phone: formattedPhone,
sender: senderId
});
return {
success: false,
error: `API returned non-JSON response: "${responseText.substring(0, 150)}" (Status: ${response.status})`
};
}
Detailed Implementation Code Reference
typescriptexport async function sendSms(phone: string, message: string): Promise<SmsResult> {
let apiUrl = process.env.BONGATECH_API_URL || '[https://bulk.bongatech.co.ke/api/v1/send-sms](https://bulk.bongatech.co.ke/api/v1/send-sms)';
if (apiUrl.includes('api.bongatech.co.ke/sms/v1/send') || apiUrl.includes('api.bongatech.co.ke')) {
apiUrl = '[https://bulk.bongatech.co.ke/api/v1/send-sms](https://bulk.bongatech.co.ke/api/v1/send-sms)';
}
const apiKey = process.env.BONGATECH_API_KEY || process.env.BONGATECH_API_TOKEN || process.env.BONGATECH_TOKEN || process.env.VERCEL_BONGATECH_API_KEY || process.env.VERCEL_BONGATECH_TOKEN;
const senderId = process.env.BONGATECH_SENDER_ID || process.env.BONGATECH_SENDERID || process.env.VERCEL_BONGATECH_SENDER_ID;
if (!apiKey || !senderId) {
const missingKeys = [];
if (!apiKey) missingKeys.push('API key/token (e.g., BONGATECH_API_KEY / BONGATECH_TOKEN)');
if (!senderId) missingKeys.push('Sender ID (e.g., BONGATECH_SENDER_ID)');
return {
success: false,
error: `BongaTech not configured: Missing ${missingKeys.join(' and ')}. Please configure these environment variables in your Vercel project settings.`
};
}
const formattedPhone = formatPhoneNumber(phone);
if (!formattedPhone) {
return { success: false, error: 'Invalid phone number: Number contains no digits.' };
}
try {
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
phone: formattedPhone,
sender: senderId,
message,
}),
});
const responseText = await response.text();
let data: any = {};
try {
data = JSON.parse(responseText);
} catch {
console.error('[BongaTech SMS Error] API returned non-JSON response:', {
status: response.status,
responseText,
phone: formattedPhone,
sender: senderId
});
return {
success: false,
error: `API returned non-JSON response: "${responseText.substring(0, 150)}" (Status: ${response.status})`
};
}
if (response.ok) {
return { success: true, messageId: data.messageId || data.id || data.message };
}
let errorMsg = data.message || data.error || '';
if (data.errors && typeof data.errors === 'object') {
const detailedErrors = Object.entries(data.errors)
.map(([field, msgs]) => `${field}: ${Array.isArray(msgs) ? msgs.join(', ') : String(msgs)}`)
.join('; ');
errorMsg = errorMsg ? `${errorMsg} (${detailedErrors})` : detailedErrors;
}
console.error('[BongaTech SMS Error] Failed API response:', {
status: response.status,
error: errorMsg,
data,
phone: formattedPhone,
sender: senderId
});
return {
success: false,
error: errorMsg || `SMS failed (Status: ${response.status}). Response: ${responseText.substring(0, 150)}`
};
} catch (error) {
console.error('[BongaTech SMS Error] Fetch or network exception:', error);
return { success: false, error: error instanceof Error ? error.message : 'Unknown error during SMS request' };
}
}