API Documentation
Welcome to the Pewang Gateway API. Build powerful messaging experiences and secure authentication flows using your own devices.
https://gateway.pewang.company/api
Send text, images, PDFs, videos via your connected WhatsApp numbers.
SMS
Send SMS via your connected Android gateway devices.
SIMCall Verifyβ’
SIM-based phone verification. Impossible to fake, 10 credits per verify.
Broadcast
Send bulk messages to multiple recipients with queue management.
Authentication
All API requests must include your API Key. You can pass it in three ways:
| Method | How | Example |
|---|---|---|
| Header (recommended) | x-api-key header |
x-api-key: sk_live_abc123... |
| Query Parameter | ?secret= in URL |
/api/sendSMS?secret=sk_live_abc123... |
| Request Body | secret field in JSON body |
{"secret": "sk_live_abc123..."} |
Generate your API key from the Developer Console β Settings β API Keys.
curl -X POST https://gateway.pewang.company/api/sendSMS \
-H "x-api-key: sk_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{"to": "254712345678", "msg": "Hello!", "client": "my_device"}'
Client ID
The client parameter identifies which connected WhatsApp number or SMS gateway device
should send your message.
Finding Your Client ID
You can find your Client ID in the Developer Console:
- Go to console.pewang.company
- Navigate to WhatsApp section
- Each connected number displays its Client ID with a copy button
The Client ID looks like: wa_abc123xyz or a custom name you've
set.
Send SMS
Send a standard SMS message via your connected Android Gateway device.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| to | string | Yes | Recipient phone number (e.g., 254712345678) |
| msg | string | Yes | Message content |
| sim | int | No | SIM slot (0 or 1). Defaults to system default. |
| client | string | Yes | Client ID of the sender device (from your dashboard) |
Response
{
"success": true,
"message": "Message queued",
"id": "550e8400-e29b-41d4-a716-446655440000"
}
Send WhatsApp
Send text messages, images, videos, and documents (PDF, DOCX, etc.) via your connected WhatsApp client.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| to | string | Yes | Recipient phone number (e.g., 254712345678 or 0712345678) |
| msg | string | Yes | Text content or URL/path to media file |
| client | string | Yes | Client ID of the sender (from your dashboard) |
| type | string | No | Message type: image, video, or document. Omit for plain text. |
| caption | string | No | Caption text to display with media (images, videos, documents) |
| fileName | string | No | Display filename for documents (e.g., report.pdf) |
| mimetype | string | No | MIME type for documents. Default: application/pdf |
Send a Text Message
curl -X POST https://gateway.pewang.company/api/sendWhatsApp \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"to": "254712345678", "msg": "Hello from our system! π", "client": "my_shop"}'
Response
{
"success": true,
"clientId": "my_shop",
"to": "254712345678@s.whatsapp.net",
"status": "queued",
"queueSize": 1
}
πΈ Send Media (Images, Videos, PDFs)
The same /api/sendWhatsApp endpoint handles all media types. Set the type parameter and pass a URL or file path as msg.
Send an Image
curl -X POST https://gateway.pewang.company/api/sendWhatsApp \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "254712345678",
"client": "hotel_reception",
"type": "image",
"msg": "https://myhotel.com/images/room-deluxe.jpg",
"caption": "π¨ Here is your room! Check-in is at 2 PM."
}'
Send a PDF Document
curl -X POST https://gateway.pewang.company/api/sendWhatsApp \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "254712345678",
"client": "hotel_reception",
"type": "document",
"msg": "https://myhotel.com/reports/daily-2026-04-15.pdf",
"caption": "π Daily Occupancy Report - April 15, 2026",
"fileName": "daily_report_2026-04-15.pdf",
"mimetype": "application/pdf"
}'
Send a Video
curl -X POST https://gateway.pewang.company/api/sendWhatsApp \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "254712345678",
"client": "hotel_reception",
"type": "video",
"msg": "https://myhotel.com/videos/room-tour.mp4",
"caption": "π₯ Take a virtual tour of our suites!"
}'
Supported Media Types
| Type | Formats | Max Size | Use Case |
|---|---|---|---|
image | JPEG, PNG, WebP | 16 MB | Photos, flyers, receipts |
video | MP4, 3GP | 16 MB | Tours, demos, tutorials |
document | PDF, DOCX, XLSX, CSV | 100 MB | Reports, invoices, contracts |
msg value.
π’ Broadcast Messages
Send the same message to multiple recipients. Messages are queued and sent with human-like delays to prevent WhatsApp rate limiting.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| recipients | array | Yes | Array of phone numbers |
| message | string | Yes | Message to send to all recipients |
| client | string | Yes | Client ID of the sender |
Example
curl -X POST https://gateway.pewang.company/api/broadcast \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client": "hotel_reception",
"message": "π Happy holidays from our hotel! Enjoy 20% off your next stay.",
"recipients": ["254712345678", "254798765432", "254700111222"]
}'
π° Credits & Pricing
Pewang Gateway uses a credit-based billing system. Credits are deducted per action:
| Action | Cost | Description |
|---|---|---|
| SMS Send | 1 credit | Each outbound SMS |
| WhatsApp Send | 1 credit | Each outbound WhatsApp (text or media) |
| WhatsApp Bot Reply | 0.5 credits | Auto-replies from your chatbot |
| AI Assistant | 5 credits | AI-generated responses |
| SIMCall Verifyβ’ | 10 credits | Per successful phone verification |
| Broadcast | 1 credit/msg | Per recipient in a broadcast |
Low Balance Alerts
You'll receive automatic WhatsApp notifications when your balance crosses these thresholds:
- 500 credits β Heads-up notice
- 100 credits β Low balance warning
- 20 credits β Urgent: very low
- 0 credits β Critical: services paused
π Billing API
Programmatically monitor your balance and usage from your application.
Check Balance
Returns your current balance, warning level, and plan.
curl https://gateway.pewang.company/api/credits/balance-check \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"balance": 342,
"sufficient": true,
"warning": null,
"plan": "Pro"
}
Usage Report
Returns per-type, per-day usage breakdown for a date range.
curl "https://gateway.pewang.company/api/user/usage-report?startDate=2026-04-01&endDate=2026-04-15" \
-H "Authorization: Bearer YOUR_TOKEN"
Billing Summary
Returns balance + full pricing table for display in your app.
curl https://gateway.pewang.company/api/user/billing-summary \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"balance": 342,
"warning": null,
"plan": "Pro",
"pricing": {
"SMS_SEND": 1,
"WHATSAPP_SEND": 1,
"WHATSAPP_BOT_REPLY": 0.5,
"AI_GENERATION": 5,
"SIMCALL_VERIFY": 10
}
}
π³ M-Pesa STK Push (Daraja)
Use this API to request payment from a customer directly from your chatbot or backend. Each gateway account can configure its own Daraja credentials in Console β Settings β M-Pesa Daraja.
x-api-key and Idempotency-Key headers. Do not pass API keys in query/body for payment routes.
Auth: x-api-key
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
phone | string | Yes | Customer phone (07... or 2547...) |
amountKes | number | Yes | Amount in KES |
accountReference | string | No | Order/account reference (max 12 chars recommended) |
transactionDesc | string | No | Short payment description |
clientId | string | No | Your WhatsApp client context for tracing |
Example
curl -X POST https://gateway.pewang.company/api/mpesa/stk-push \
-H "x-api-key: YOUR_API_KEY" \
-H "Idempotency-Key: 7f4a6f03-15e4-42a0-a40c-12f91234abcd" \
-H "Content-Type: application/json" \
-d '{
"phone": "254712345678",
"amountKes": 1500,
"accountReference": "ORDER1001",
"transactionDesc": "Shoes",
"clientId": "shop_whatsapp"
}'
Response
{
"success": true,
"message": "Check your phone for M-Pesa PIN prompt.",
"data": {
"checkoutRequestId": "ws_CO_260420261234567890123",
"merchantRequestId": "29115-34620561-1",
"amountKes": 1500,
"phone254": "254712345678"
}
}
Check STK status
Use this if you want polling fallback in addition to webhook events.
Receipt Download
Returns an official PDF receipt for a successful transaction you own.
Reconciliation APIs
Returns transaction rows for external systems (loan, ERP, bank core, collections).
Returns totals for success/pending/failed/mismatch in a reporting window.
Integration Downloads
π§ͺ Testing with Postman
Postman is the easiest way to test the Pewang Gateway API. Follow these steps:
Step 1: Set Up Environment
Create a Postman Environment with these variables:
| Variable | Value |
|---|---|
base_url | https://gateway.pewang.company/api |
api_key | Your API key from the Developer Console |
client_id | Your connected device Client ID |
Step 2: Send a WhatsApp Text
Create a new request in Postman:
- Method: POST
- URL:
{{base_url}}/sendWhatsApp - Headers:
x-api-key: {{api_key}}andContent-Type: application/json
Body (raw JSON):
{
"to": "254712345678",
"msg": "Hello from Postman! π",
"client": "{{client_id}}"
}
Step 3: Send an Image
Same setup, but change the body:
{
"to": "254712345678",
"msg": "https://picsum.photos/800/600",
"client": "{{client_id}}",
"type": "image",
"caption": "Test image from Postman πΈ"
}
Step 4: Send a PDF Document
{
"to": "254712345678",
"msg": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
"client": "{{client_id}}",
"type": "document",
"caption": "Quarterly Report Q1 2026",
"fileName": "Q1_Report_2026.pdf",
"mimetype": "application/pdf"
}
Step 5: Send SMS
- Method: POST
- URL:
{{base_url}}/sendSMS
{
"to": "254712345678",
"msg": "Your OTP is 4829. Valid for 5 minutes.",
"client": "{{client_id}}"
}
https://gateway.pewang.company/api/sendWhatsApp?to=254712345678&msg=Hello&client=YOUR_CLIENT&secret=YOUR_KEY
β οΈ Error Codes
All API responses include a success boolean. When false, an error field explains the issue.
| HTTP Code | Error | Meaning | Fix |
|---|---|---|---|
401 | Missing API Key | No secret or x-api-key provided | Add your API key to the request |
403 | Invalid API Key | API key is wrong or deactivated | Check your key in the Console |
403 | Insufficient credits | Balance too low for this action | Top up credits in the Console |
403 | Account suspended | Your account has been disabled | Contact support |
400 | Missing required fields | to, msg, or client is missing | Include all required params |
500 | Client not connected | The WhatsApp device is offline | Re-scan QR code in Console |
Error Response Format
{
"success": false,
"error": "Insufficient credits",
"required": 1,
"balance": 0
}
π SIMCall Verifyβ’
Secure, SIM-based authentication that's impossible to fake. 10 credits per successful verification.
Pay Per Success
Only pay 10 credits when a user is successfully verified. No setup fees.
Impossible to Fake
Requires physical possession of the SIM card to answer the verification call.
Instant
3-25 second verification times. Faster than waiting for SMS delivery.
Global
Works in any country. No carrier integration or sender ID registration needed.
How It Works
SIMCall Verifyβ’ uses a challenge-response protocol based on call duration timing:
- Challenge Created - Server generates random target duration (3-25s)
- Call Placed - User receives call from verification system
- User Answers & Holds - Must hold call for exact duration
- User Hangs Up - Timing measured server-side
- Validation - Duration within window = verified β
// Example Challenge
{
"challengeId": "abc-123",
"targetDuration": 12000, // 12 seconds
"minTime": 11000, // 11s (tolerance: Β±1s)
"maxTime": 13000, // 13s
"expiresAt": 1735672030000 // 30s validity
}
π‘οΈ Security Features
| Feature | Description |
|---|---|
| Rate Limiting | 3 failed attempts in 5 min β 30 min cooldown |
| SIM Pool | Multiple devices, health monitoring, auto-recovery |
| Queue System | FIFO processing with ETA estimation |
| State Machine | 13-state strict flow prevents logic errors |
| Challenge Expiry | 30-second validity window |
Integration Guide
Integrate SIMCall Verifyβ’ in 3 simple steps:
Step 1: Initiate Verification
| Parameter | Type | Required | Description |
|---|---|---|---|
| phoneNumber | string | Yes | Phone number to verify (international format: +254711...) |
Response:
{
"success": true,
"challengeId": "550e8400-e29b-41d4-a716-446655440000",
"queuePosition": 1,
"eta": 15000, // milliseconds
"message": "Verification queued. You will receive a call shortly."
}
Step 2: Poll for Status
Response:
{
"success": true,
"status": "SUCCESS", // or "PENDING", "FAILED"
"verified": true,
"reason": "Verified"
}
Step 3: Handle Result
Poll every 2-3 seconds until status is SUCCESS or FAILED.
Code Examples
Ready-to-use examples in popular languages:
JavaScript / Node.js
const axios = require('axios');
async function verifySIMCall(phoneNumber) {
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://gateway.pewang.company/api';
// Step 1: Initiate verification
const { data } = await axios.post(
`${BASE_URL}/simcall/initiate`,
{ phoneNumber },
{ headers: { 'x-api-key': API_KEY } }
);
if (!data.success) throw new Error(data.error);
const challengeId = data.challengeId;
console.log(`Verification queued. ETA: ${data.eta / 1000}s`);
// Step 2: Poll for status
while (true) {
await new Promise(r => setTimeout(r, 3000)); // Wait 3s
const { data: status } = await axios.get(
`${BASE_URL}/simcall/status/${challengeId}`,
{ headers: { 'x-api-key': API_KEY } }
);
if (status.status === 'SUCCESS') {
console.log('β
Verified!');
return true;
}
if (status.status === 'FAILED') {
console.log(`β Failed: ${status.reason}`);
return false;
}
}
}
// Usage
verifySIMCall('+254711234567');
Python
import requests
import time
def verify_simcall(phone_number):
API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://gateway.pewang.company/api'
headers = {'x-api-key': API_KEY}
# Step 1: Initiate
response = requests.post(
f'{BASE_URL}/simcall/initiate',
json={'phoneNumber': phone_number},
headers=headers
)
data = response.json()
if not data['success']:
raise Exception(data['error'])
challenge_id = data['challengeId']
print(f"Queued. ETA: {data['eta'] / 1000}s")
# Step 2: Poll
while True:
time.sleep(3)
status = requests.get(
f'{BASE_URL}/simcall/status/{challenge_id}',
headers=headers
).json()
if status['status'] == 'SUCCESS':
print('β
Verified!')
return true
if status['status'] == 'FAILED':
print(f"β Failed: {status['reason']}")
return false
# Usage
verify_simcall('+254711234567')
PHP
<?php
function verifySIMCall($phoneNumber) {
$apiKey = 'YOUR_API_KEY';
$baseUrl = 'https://gateway.pewang.company/api';
// Step 1: Initiate
$ch = curl_init("$baseUrl/simcall/initiate");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'phoneNumber' => $phoneNumber
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
"x-api-key: $apiKey"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
if (!$response['success']) {
throw new Exception($response['error']);
}
$challengeId = $response['challengeId'];
echo "Queued. ETA: " . ($response['eta'] / 1000) . "s\n";
// Step 2: Poll
while (true) {
sleep(3);
$ch = curl_init("$baseUrl/simcall/status/$challengeId");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-api-key: $apiKey"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$status = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($status['status'] === 'SUCCESS') {
echo "β
Verified!\n";
return true;
}
if ($status['status'] === 'FAILED') {
echo "β Failed: {$status['reason']}\n";
return false;
}
}
}
// Usage
verifySIMCall('+254711234567');
?>
Java
import java.net.http.*;
import com.google.gson.*;
public class SIMCallVerify {
private static final String API_KEY = "YOUR_API_KEY";
private static final String BASE_URL = "https://gateway.pewang.company/api";
public static boolean verify(String phoneNumber) throws Exception {
HttpClient client = HttpClient.newHttpClient();
Gson gson = new Gson();
// Step 1: Initiate
String json = gson.toJson(Map.of("phoneNumber", phoneNumber));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/simcall/initiate"))
.header("x-api-key", API_KEY)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
JsonObject data = gson.fromJson(response.body(), JsonObject.class);
String challengeId = data.get("challengeId").getAsString();
System.out.println("Queued. ETA: " + data.get("eta").getAsInt() / 1000 + "s");
// Step 2: Poll
while (true) {
Thread.sleep(3000);
request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/simcall/status/" + challengeId))
.header("x-api-key", API_KEY)
.GET()
.build();
response = client.send(request, HttpResponse.BodyHandlers.ofString());
JsonObject status = gson.fromJson(response.body(), JsonObject.class);
String state = status.get("status").getAsString();
if (state.equals("SUCCESS")) {
System.out.println("β
Verified!");
return true;
}
if (state.equals("FAILED")) {
System.out.println("β Failed");
return false;
}
}
}
}
C# / .NET
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
public class SIMCallVerify
{
private const string API_KEY = "YOUR_API_KEY";
private const string BASE_URL = "https://gateway.pewang.company/api";
public static async Task<bool> Verify(string phoneNumber)
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", API_KEY);
// Step 1: Initiate
var payload = new { phoneNumber };
var content = new StringContent(
JsonSerializer.Serialize(payload),
System.Text.Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
$"{BASE_URL}/simcall/initiate",
content
);
var data = await JsonSerializer.DeserializeAsync<JsonElement>(
await response.Content.ReadAsStreamAsync()
);
var challengeId = data.GetProperty("challengeId").GetString();
Console.WriteLine($"Queued. ETA: {data.GetProperty(\"eta\").GetInt32() / 1000}s");
// Step 2: Poll
while (true)
{
await Task.Delay(3000);
response = await client.GetAsync(
$"{BASE_URL}/simcall/status/{challengeId}"
);
var status = await JsonSerializer.DeserializeAsync<JsonElement>(
await response.Content.ReadAsStreamAsync()
);
var state = status.GetProperty("status").GetString();
if (state == "SUCCESS")
{
Console.WriteLine("β
Verified!");
return true;
}
if (state == "FAILED")
{
Console.WriteLine("β Failed");
return false;
}
}
}
}
Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
const (
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://gateway.pewang.company/api"
)
func verifySIMCall(phoneNumber string) (bool, error) {
client := &http.Client{}
// Step 1: Initiate
payload, _ := json.Marshal(map[string]string{
"phoneNumber": phoneNumber,
})
req, _ := http.NewRequest("POST", BASE_URL+"/simcall/initiate",
bytes.NewBuffer(payload))
req.Header.Set("x-api-key", API_KEY)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)
challengeId := data["challengeId"].(string)
fmt.Printf("Queued. ETA: %.0fs\n", data["eta"].(float64)/1000)
// Step 2: Poll
for {
time.Sleep(3 * time.Second)
req, _ = http.NewRequest("GET",
fmt.Sprintf("%s/simcall/status/%s", BASE_URL, challengeId), nil)
req.Header.Set("x-api-key", API_KEY)
resp, _ = client.Do(req)
json.NewDecoder(resp.Body).Decode(&data)
resp.Body.Close()
status := data["status"].(string)
if status == "SUCCESS" {
fmt.Println("β
Verified!")
return true, nil
}
if status == "FAILED" {
fmt.Println("β Failed")
return false, nil
}
}
}
Ruby
require 'net/http'
require 'json'
def verify_simcall(phone_number)
api_key = 'YOUR_API_KEY'
base_url = 'https://gateway.pewang.company/api'
# Step 1: Initiate
uri = URI("#{base_url}/simcall/initiate")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request['x-api-key'] = api_key
request['Content-Type'] = 'application/json'
request.body = { phoneNumber: phone_number }.to_json
response = http.request(request)
data = JSON.parse(response.body)
challenge_id = data['challengeId']
puts "Queued. ETA: #{data['eta'] / 1000}s"
# Step 2: Poll
loop do
sleep(3)
uri = URI("#{base_url}/simcall/status/#{challenge_id}")
request = Net::HTTP::Get.new(uri.path)
request['x-api-key'] = api_key
response = http.request(request)
status = JSON.parse(response.body)
if status['status'] == 'SUCCESS'
puts 'β
Verified!'
return true
elsif status['status'] == 'FAILED'
puts "β Failed: #{status['reason']}"
return false
end
end
end
# Usage
verify_simcall('+254711234567')
Best Practices
β Do's
- Use international format - Always include country code (+254...)
- Poll every 2-3 seconds - Don't overwhelm the server
- Handle rate limits gracefully - Show user-friendly error messages
- Set timeout - Stop polling after 60 seconds
- Show ETA to users - Use the
etafield for better UX - Log failures - Track verification failures for debugging
β Don'ts
- Don't poll too frequently - < 2 seconds wastes resources
- Don't retry immediately on failure - Respect rate limits
- Don't expose API keys - Keep them server-side only
- Don't skip validation - Always check
successfield - Don't use for high-frequency auth - Best for login, not every API call
π― Use Cases
| Use Case | Why SIMCall Verify? |
|---|---|
| User Login | Passwordless, zero-cost authentication |
| Phone Verification | Prove SIM ownership without SMS costs |
| 2FA / MFA | Second factor that can't be phished |
| Account Recovery | Verify identity for password reset |
| High-Value Transactions | Extra security for payments, transfers |
π‘ Pro Tip
Combine SIMCall Verify with traditional methods for a hybrid approach: Use SIMCall for high-security actions (login, payments) and SMS/email for low-security notifications.
Webhooks
Configure a Webhook URL in your dashboard settings to receive real-time updates about message status, incoming messages, and billing events.
Pewang Gateway sends POST requests to your URL with a JSON body.
Deliveries include event metadata headers and automatic retry attempts for transient failures.
Webhook Headers
| Header | Description |
|---|---|
X-Pewang-Event-Id | Unique event delivery ID |
X-Pewang-Timestamp | ISO timestamp used in signature payload |
X-Pewang-Retry | Retry counter (1..3) |
X-Pewang-Signature | sha256=... HMAC signature if secret configured |
Webhook Events
Message Sent
Triggered when a message is successfully sent/queued.
{
"event": "message.sent",
"timestamp": "2026-04-15T10:00:00Z",
"data": {
"id": "550e8400-e29b-41d4...",
"to": "254712345678",
"type": "WHATSAPP",
"status": "QUEUED"
}
}
Message Received (Incoming)
Triggered when a customer sends a message to your connected number.
{
"event": "message.received",
"timestamp": "2026-04-15T10:01:00Z",
"data": {
"type": "WHATSAPP",
"from": "254712345678",
"body": "I'd like to book a room",
"clientId": "hotel_reception"
}
}
Low Balance Alert
Triggered when your credit balance drops below a threshold.
{
"event": "balance.low",
"timestamp": "2026-04-15T14:30:00Z",
"data": {
"currentBalance": 18,
"threshold": 20,
"severity": "critical"
}
}
M-Pesa Webhook Events
When Daraja STK is enabled for your account, the gateway can push payment lifecycle events to your webhook URL.
STK Initiated
{
"event": "mpesa.stk_initiated",
"timestamp": "2026-04-26T08:40:00Z",
"data": {
"checkoutRequestId": "ws_CO_...",
"merchantRequestId": "29115-...",
"amountKes": 1500,
"phone254": "254712345678",
"clientId": "shop_whatsapp"
}
}
STK Completed
{
"event": "mpesa.stk_completed",
"timestamp": "2026-04-26T08:41:10Z",
"data": {
"checkoutRequestId": "ws_CO_...",
"mpesaReceiptNumber": "QWE12RTY34",
"amountKes": 1500,
"phone254": "254712345678",
"status": "success"
}
}
STK Failed
{
"event": "mpesa.stk_failed",
"timestamp": "2026-04-26T08:41:10Z",
"data": {
"checkoutRequestId": "ws_CO_...",
"resultCode": 1032,
"resultDesc": "Request cancelled by user",
"amountKes": 1500
}
}
π‘ Real-World Integration Examples
Here's how developers integrate the Pewang Gateway into real business systems:
π¨ Hotel Management System
// Node.js β Send check-in confirmation with room photo
const axios = require('axios');
async function sendCheckInConfirmation(guestPhone, guestName, roomNumber) {
await axios.post('https://gateway.pewang.company/api/sendWhatsApp', {
to: guestPhone,
client: 'hotel_reception',
type: 'image',
msg: `https://myhotel.com/rooms/${roomNumber}/photo.jpg`,
caption: `Welcome ${guestName}! π¨\n\nRoom: ${roomNumber}\nCheck-in: 2:00 PM\nWiFi: HotelGuest / pass1234\n\nEnjoy your stay!`
}, { headers: { 'x-api-key': process.env.PEWANG_KEY } });
}
// Send daily report PDF to hotel manager
async function sendDailyReport(managerPhone) {
const today = new Date().toISOString().split('T')[0];
await axios.post('https://gateway.pewang.company/api/sendWhatsApp', {
to: managerPhone,
client: 'hotel_reception',
type: 'document',
msg: `https://myhotel.com/api/reports/daily/${today}.pdf`,
caption: `π Daily Report β ${today}`,
fileName: `hotel_report_${today}.pdf`,
mimetype: 'application/pdf'
}, { headers: { 'x-api-key': process.env.PEWANG_KEY } });
}
π E-Commerce Order Notifications
# Python β Send order confirmation + invoice PDF
import requests
def send_order_confirmation(phone, order_id, total):
requests.post('https://gateway.pewang.company/api/sendWhatsApp', json={
'to': phone,
'client': 'shop_whatsapp',
'msg': f'β
Order #{order_id} confirmed!\n\nπ° Total: KES {total:,.0f}\nπ¦ Delivery: 2-3 business days\n\nThank you for shopping with us! ποΈ'
}, headers={'x-api-key': 'sk_live_...'})
def send_invoice(phone, order_id):
requests.post('https://gateway.pewang.company/api/sendWhatsApp', json={
'to': phone,
'client': 'shop_whatsapp',
'type': 'document',
'msg': f'https://myshop.co.ke/invoices/{order_id}.pdf',
'caption': f'π§Ύ Invoice for Order #{order_id}',
'fileName': f'invoice_{order_id}.pdf',
'mimetype': 'application/pdf'
}, headers={'x-api-key': 'sk_live_...'})
π₯ Clinic Appointment Reminders
// PHP β Remind patients of upcoming appointments
<?php
function sendAppointmentReminder($phone, $doctor, $date, $time) {
$ch = curl_init('https://gateway.pewang.company/api/sendWhatsApp');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'to' => $phone,
'client' => 'clinic_wa',
'msg' => "π₯ *Appointment Reminder*\n\n"
. "π¨ββοΈ Dr. $doctor\n"
. "π
$date at $time\n\n"
. "Reply YES to confirm or CANCEL to reschedule."
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'x-api-key: sk_live_...'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result, true);
}
?>
π± Android App β Kotlin (OTP & Notifications)
// Kotlin β Send OTP via WhatsApp from your Android backend
import okhttp3.*
import org.json.JSONObject
class PewangGateway(private val apiKey: String) {
private val client = OkHttpClient()
private val baseUrl = "https://gateway.pewang.company/api"
// Send OTP code via WhatsApp
fun sendOTP(phone: String, otp: String) {
val json = JSONObject().apply {
put("to", phone)
put("client", "my_app_wa")
put("msg", "π *Your OTP Code*\n\n" +
"Code: *$otp*\n" +
"Valid for 5 minutes.\n\n" +
"Do not share this code with anyone.")
}
val body = RequestBody.create(
MediaType.parse("application/json"), json.toString()
)
val request = Request.Builder()
.url("$baseUrl/sendWhatsApp")
.addHeader("x-api-key", apiKey)
.post(body).build()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
println("β
OTP sent: ${response.body()?.string()}")
}
override fun onFailure(call: Call, e: IOException) {
println("β Failed: ${e.message}")
}
})
}
// Send receipt image after payment
fun sendReceipt(phone: String, receiptUrl: String, amount: String) {
val json = JSONObject().apply {
put("to", phone)
put("client", "my_app_wa")
put("type", "image")
put("msg", receiptUrl)
put("caption", "β
Payment of KES $amount received!\nThank you for your purchase.")
}
// ... same request pattern
}
}
π± Flutter / Dart (Delivery Tracking)
// Flutter β Send delivery updates to customers
import 'package:http/http.dart' as http;
import 'dart:convert';
class PewangGateway {
static const _baseUrl = 'https://gateway.pewang.company/api';
final String apiKey;
final String clientId;
PewangGateway({required this.apiKey, required this.clientId});
// Send order status update
Future<bool> sendDeliveryUpdate(String phone, String orderId, String status) async {
final messages = {
'confirmed': 'β
Order #$orderId confirmed! Preparing now...',
'preparing': 'π¨βπ³ Order #$orderId is being prepared!',
'on_the_way': 'π Your rider is on the way with order #$orderId!',
'delivered': 'π¦ Order #$orderId delivered! Thank you! β',
};
final response = await http.post(
Uri.parse('$_baseUrl/sendWhatsApp'),
headers: {
'x-api-key': apiKey,
'Content-Type': 'application/json',
},
body: jsonEncode({
'to': phone,
'client': clientId,
'msg': messages[status] ?? 'Order update for #$orderId',
}),
);
return response.statusCode == 200;
}
// Send invoice PDF to customer
Future<bool> sendInvoice(String phone, String invoiceUrl, String orderId) async {
final response = await http.post(
Uri.parse('$_baseUrl/sendWhatsApp'),
headers: {'x-api-key': apiKey, 'Content-Type': 'application/json'},
body: jsonEncode({
'to': phone,
'client': clientId,
'type': 'document',
'msg': invoiceUrl,
'caption': 'π§Ύ Invoice for Order #$orderId',
'fileName': 'invoice_$orderId.pdf',
'mimetype': 'application/pdf',
}),
);
return response.statusCode == 200;
}
}
π± React Native (Food Ordering App)
// React Native β WhatsApp notifications for a food ordering app
const PEWANG_API = 'https://gateway.pewang.company/api';
const API_KEY = 'sk_live_...';
const CLIENT = 'restaurant_wa';
// Call from your backend (NOT from the React Native app directly!)
export const sendOrderConfirmation = async (phone, items, total) => {
const itemList = items.map(i => `β’ ${i.name} x${i.qty}`).join('\n');
await fetch(`${PEWANG_API}/sendWhatsApp`, {
method: 'POST',
headers: {
'x-api-key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: phone,
client: CLIENT,
msg: `π *Order Confirmed!*\n\n${itemList}\n\nπ° Total: KES ${total}\nβ±οΈ Ready in 25-30 mins\n\nTrack: https://myapp.com/track/ORDER123`
})
});
};
// Send menu image with daily specials
export const sendDailySpecials = async (phone, menuImageUrl) => {
await fetch(`${PEWANG_API}/sendWhatsApp`, {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
to: phone, client: CLIENT,
type: 'image',
msg: menuImageUrl,
caption: "π½οΈ Today's Specials! Order now and get 10% off π"
})
});
};
π« School Management System
// Node.js β Notify parents of student activities
const axios = require('axios');
const PEWANG = { url: 'https://gateway.pewang.company/api', key: 'sk_live_...' };
// Fee reminder with payment slip
async function sendFeeReminder(parentPhone, studentName, amount, term) {
await axios.post(`${PEWANG.url}/sendWhatsApp`, {
to: parentPhone,
client: 'school_admin',
type: 'document',
msg: `https://school.example.com/fees/${studentName}/invoice.pdf`,
caption: `π *Fee Reminder β ${term}*\n\nStudent: ${studentName}\nAmount Due: KES ${amount}\nDeadline: End of month\n\nPay via M-Pesa: 522522, A/C: SCHOOL`,
fileName: `fee_invoice_${term}.pdf`
}, { headers: { 'x-api-key': PEWANG.key } });
}
// Exam results broadcast to all parents
async function broadcastExamResults(parentPhones) {
await axios.post(`${PEWANG.url}/broadcast`, {
client: 'school_admin',
message: 'π *End of Term Results*\n\nResults are now available on the parent portal.\n\nπ https://portal.school.example.com/results\n\nLogin with your registered email.',
recipients: parentPhones
}, { headers: { 'x-api-key': PEWANG.key } });
}
π Real Estate / Property Management
# Python β Property listing notifications with photos
import requests
def send_property_listing(phone, property_data):
"""Send new property listing with photo to potential buyer"""
API = {'url': 'https://gateway.pewang.company/api', 'key': 'sk_live_...'}
# Send property photo
requests.post(f"{API['url']}/sendWhatsApp", json={
'to': phone,
'client': 'agency_wa',
'type': 'image',
'msg': property_data['photo_url'],
'caption': (
f"π *New Listing: {property_data['title']}*\n\n"
f"π {property_data['location']}\n"
f"ποΈ {property_data['bedrooms']} Bed | πΏ {property_data['bathrooms']} Bath\n"
f"π° KES {property_data['price']:,.0f}/month\n\n"
f"Available from: {property_data['available_date']}\n"
f"Reply BOOK to schedule a viewing!"
)
}, headers={'x-api-key': API['key']})
def send_rent_reminder(phone, tenant_name, amount, unit):
"""Monthly rent reminder"""
requests.post('https://gateway.pewang.company/api/sendWhatsApp', json={
'to': phone,
'client': 'agency_wa',
'msg': (
f"ποΈ *Rent Reminder*\n\n"
f"Dear {tenant_name},\n"
f"Unit: {unit}\n"
f"Amount: KES {amount:,.0f}\n"
f"Due: 5th of this month\n\n"
f"M-Pesa Paybill: 247247\nA/C: {unit}"
)
}, headers={'x-api-key': 'sk_live_...'})
π§ SaaS Platform (Multi-Tenant)
// Go β SaaS platform integrating Pewang for customer notifications
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type PewangClient struct {
APIKey string
ClientID string
}
func (p *PewangClient) SendWhatsApp(to, msg string) error {
payload, _ := json.Marshal(map[string]string{
"to": to, "client": p.ClientID, "msg": msg,
})
req, _ := http.NewRequest("POST",
"https://gateway.pewang.company/api/sendWhatsApp",
bytes.NewBuffer(payload))
req.Header.Set("x-api-key", p.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil { return err }
defer resp.Body.Close()
fmt.Printf("Sent to %s: %d\n", to, resp.StatusCode)
return nil
}
func SendDocument(p *PewangClient, to, docUrl, caption, fileName string) error {
payload, _ := json.Marshal(map[string]string{
"to": to, "client": p.ClientID,
"type": "document", "msg": docUrl,
"caption": caption, "fileName": fileName,
"mimetype": "application/pdf",
})
req, _ := http.NewRequest("POST",
"https://gateway.pewang.company/api/sendWhatsApp",
bytes.NewBuffer(payload))
req.Header.Set("x-api-key", p.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil { return err }
defer resp.Body.Close()
return nil
}
// Usage: Each SaaS tenant gets their own Pewang client
func main() {
hotel := &PewangClient{APIKey: "sk_live_HOTEL_KEY", ClientID: "hotel_wa"}
shop := &PewangClient{APIKey: "sk_live_SHOP_KEY", ClientID: "shop_wa"}
hotel.SendWhatsApp("254712345678", "Welcome to our hotel! π¨")
shop.SendWhatsApp("254798765432", "Your order is ready! π¦")
}
π€ Harambee & Community Fundraising
// Node.js β collect Harambee contributions with references
const axios = require('axios');
async function collectHarambee(phone, amountKes) {
const idempotencyKey = `harambee-${Date.now()}-${phone}`;
return axios.post('https://gateway.pewang.company/api/mpesa/stk-push', {
phone,
amountKes,
accountReference: 'HARAMBEE-APR2026',
transactionDesc: 'Fundraising',
clientId: 'harambee_bot'
}, {
headers: {
'x-api-key': process.env.PEWANG_KEY,
'Idempotency-Key': idempotencyKey
}
});
}
ποΈ Events Ticketing + Gate Reconciliation
# Python β ticket payment + reconciliation export
import requests
requests.post('https://gateway.pewang.company/api/mpesa/stk-push', json={
'phone': '254712345678',
'amountKes': 1500,
'accountReference': 'TICKET-A',
'transactionDesc': 'EventTicket',
'clientId': 'events_bot'
}, headers={
'x-api-key': 'sk_live_...',
'Idempotency-Key': 'ticket-001-unique'
})
report = requests.get(
'https://gateway.pewang.company/api/mpesa/transactions?from=2026-04-01T00:00:00.000Z&to=2026-04-30T23:59:59.999Z&status=success',
headers={'x-api-key': 'sk_live_...'}
).json()
π Birthday / Group Gifting
// WhatsApp command examples for gift pooling
// PAY500BIRTHDAY-JANE
// LIPA1000BIRTHDAY-JANE
// PAY250GIFT-KEVIN
// Use accountReference to group all contributions, then pull summary:
// GET /api/mpesa/reconciliation/summary?from=...&to=...
π’ WhatsApp Marketing Guide
Turn WhatsApp into your most powerful sales channel. The Pewang Gateway gives you everything you need to reach customers instantly, promote products, send offers, and close sales β all through WhatsApp.
- 98% open rate β compared to 20% for email
- 45% response rate β 10x higher than SMS
- Instant delivery β messages arrive in seconds
- Rich media β send images, videos, PDFs, catalogs
- Personal touch β customers already use WhatsApp daily
π Use Case: Shoe Shop β Product Launch Campaign
Send a product launch blast to your entire customer list with images and a direct order link:
// Node.js β Product Launch Broadcast Campaign
const axios = require('axios');
const API_KEY = 'your_api_key';
const BASE_URL = 'https://gateway.pewang.company';
const CLIENT_ID = 'your_client_id';
// Customer list from your database
const customers = [
{ phone: '254712345678', name: 'John' },
{ phone: '254713456789', name: 'Mary' },
{ phone: '254714567890', name: 'Peter' },
// ... up to 500+ contacts
];
async function sendProductLaunch() {
for (const customer of customers) {
try {
// Send product image with personalized message
await axios.post(`${BASE_URL}/api/messages/send`, {
clientId: CLIENT_ID,
to: customer.phone,
type: 'image',
imageUrl: 'https://yourshop.com/new-jordans.jpg',
caption: `π *Hey ${customer.name}!* \n\n` +
`*NEW DROP!* Jordan 1 Retro High \ud83d\udd25\n\n` +
`\u2b50 Limited Edition\n` +
`\ud83d\udcb0 KES 15,000 (was KES 18,500)\n` +
`\ud83d\udce6 Free delivery in Nairobi\n\n` +
`Reply *ORDER* to grab yours before they sell out!`
}, {
headers: { 'x-api-key': API_KEY }
});
console.log(`\u2705 Sent to ${customer.name}`);
// 2-second delay to avoid rate limiting
await new Promise(r => setTimeout(r, 2000));
} catch (err) {
console.error(`\u274c Failed for ${customer.name}:`, err.message);
}
}
}
sendProductLaunch();
π₯ Use Case: LPG Gas β Refill Reminder Campaign
Automate refill reminders to customers who bought gas 3-4 weeks ago:
# Python β Automated Gas Refill Reminders
import requests
import time
from datetime import datetime, timedelta
API_KEY = "your_api_key"
BASE_URL = "https://gateway.pewang.company"
CLIENT_ID = "your_client_id"
# Customers who last ordered 25+ days ago
customers_due = [
{"phone": "254712345678", "name": "Mama Njeri", "gas_size": "13kg"},
{"phone": "254713456789", "name": "Mr. Ochieng", "gas_size": "6kg"},
]
def send_refill_reminders():
for customer in customers_due:
message = (
f"π₯ *Hi {customer['name']}!*\n\n"
f"It's been about a month since your last "
f"{customer['gas_size']} gas refill.\n\n"
f"\u26fd *Time for a top-up?*\n\n"
f"\u2713 {customer['gas_size']} Refill \u2014 "
f"{('KES 1,800' if customer['gas_size'] == '6kg' else 'KES 3,200')}\n"
f"\u2713 Free Delivery\n"
f"\u2713 30-min delivery\n\n"
f"Reply *YES* to order now!"
)
response = requests.post(
f"{BASE_URL}/api/messages/send",
json={
"clientId": CLIENT_ID,
"to": customer["phone"],
"message": message
},
headers={"x-api-key": API_KEY}
)
print(f"\u2705 Reminder sent to {customer['name']}")
time.sleep(2)
send_refill_reminders()
π¦ Use Case: E-Commerce β Flash Sale Broadcast
Run a flash sale campaign using the Broadcast API to reach all your customers at once:
// PHP β Flash Sale Broadcast with Product Image
<?php
$apiKey = 'your_api_key';
$baseUrl = 'https://gateway.pewang.company';
$clientId = 'your_client_id';
// Load customer list from database
$customers = [
['phone' => '254712345678', 'name' => 'Customer 1'],
['phone' => '254713456789', 'name' => 'Customer 2'],
];
foreach ($customers as $customer) {
$data = [
'clientId' => $clientId,
'to' => $customer['phone'],
'type' => 'image',
'imageUrl' => 'https://yourshop.com/flash-sale-banner.jpg',
'caption' => "π₯ *FLASH SALE β 3 HOURS ONLY!* π₯\n\n"
. "Hi {$customer['name']}!\n\n"
. "β *50% OFF* all items\n"
. "π Free delivery countrywide\n"
. "β° Sale ends at 9 PM tonight!\n\n"
. "Reply *SHOP* to see products"
];
$ch = curl_init("{$baseUrl}/api/messages/send");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
"x-api-key: {$apiKey}"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
echo "\u2705 Sent to {$customer['name']}\n";
sleep(2); // Rate limiting
}
?>
π Use Case: Scheduled Promotions
Schedule promotional messages to go out at the best time using our Broadcast API:
// Node.js β Schedule a promotional broadcast for tomorrow 9 AM
const axios = require('axios');
async function schedulePromotion() {
const tomorrow9am = new Date();
tomorrow9am.setDate(tomorrow9am.getDate() + 1);
tomorrow9am.setHours(9, 0, 0, 0);
const response = await axios.post('https://gateway.pewang.company/api/broadcast', {
clientId: 'your_client_id',
recipients: [
'254712345678', '254713456789',
'254714567890', '254715678901'
],
message: '\ud83c\udf89 *WEEKEND SPECIAL!* \ud83c\udf89\n\n'
+ 'Buy any 2 items and get the 3rd *FREE!*\n\n'
+ '\ud83d\uded2 Shop now: yourshop.com\n'
+ '\ud83d\udcde WhatsApp us to order\n\n'
+ 'Offer valid this weekend only! \u23f0',
scheduledAt: tomorrow9am.toISOString()
}, {
headers: {
'Authorization': 'Bearer your_token',
'Content-Type': 'application/json'
}
});
console.log('\u2705 Campaign scheduled!', response.data);
}
schedulePromotion();
π£ Marketing Campaign Strategies
Here are proven marketing strategies you can run through the Pewang Gateway:
| Campaign Type | Best For | How to Run |
|---|---|---|
| π₯ Flash Sales | Shoes, clothing, electronics | Broadcast API with product image + limited-time offer |
| π Refill Reminders | LPG gas, water, subscriptions | Scheduled messages based on last purchase date |
| π Loyalty Programs | Any repeat-purchase business | Bot flow with VIP club join + automated rewards |
| π¦ New Product Launch | Any product business | Image broadcast with early-bird pricing |
| π Customer Reviews | Hotels, restaurants, services | Automated follow-up message after service delivery |
| π Catalogs & Price Lists | Wholesalers, distributors | Send PDF documents via the media API |
| π₯ Video Demos | Tech products, beauty, food | Send product demo videos via the media API |
π€ Automated Marketing Bot
The most powerful feature: set up a bot that turns every incoming WhatsApp message into a sales opportunity.
When a customer texts your number, the bot can automatically:
- Show your product catalog with prices
- Share product images and videos
- Collect orders (item + size + delivery location)
- Send payment instructions (M-Pesa, bank details)
- Offer exclusive discounts to new customers
- Run 24/7 β never miss a sale!
- Log in to your Console Dashboard
- Go to Developer β Bot Flow Builder β click Templates β choose Shoe Shop, LPG Gas, or Product Marketing
- Customize texts with your prices and products β click Save & Deploy
Your marketing bot is live in under 5 minutes! π
π Best Practices
- Personalize messages β Use customer names for 2x higher response rates
- Include images β Visual product photos get 3x more engagement
- Time it right β Send between 9 AM-12 PM or 5 PM-8 PM for best results
- Add urgency β "Ends tonight!", "Only 5 left!" drive faster action
- Use WhatsApp formatting β *bold* for emphasis, _italic_ for subtlety
- Include a clear CTA β "Reply ORDER", "Reply YES", "Click this link"
- Don't spam β Max 2-3 promotional messages per week per customer
- Segment your list β Send relevant offers to the right audience
ποΈ WhatsApp E-Commerce Shop
Turn your WhatsApp number into a full online store. Customers can browse products, add to cart, receive invoices, pay via M-Pesa, and track their orders β all within a WhatsApp chat.
- π€ Customer texts your WhatsApp number
- π€ Bot shows welcome + product categories
- π Customer browses β selects items β adds to cart
- π Bot generates personalized invoice with totals
- π³ Customer pays via M-Pesa (Paybill/Till)
- β You confirm payment β dispatch order
- π Customer tracks delivery via WhatsApp
π» Full E-Commerce Bot Integration (Node.js)
Here's how a developer builds a complete WhatsApp shop backend that handles orders and generates invoices:
// Node.js β WhatsApp E-Commerce Order Handler
const axios = require('axios');
const API_KEY = 'your_api_key';
const BASE_URL = 'https://gateway.pewang.company';
const CLIENT_ID = 'your_client_id';
// In-memory cart (use database in production)
const carts = {};
const products = {
'1': { name: 'Floral Maxi Dress', price: 2500 },
'2': { name: 'Bodycon Dress', price: 1800 },
'3': { name: 'Nike Air Max', price: 8500 },
'4': { name: '13kg Gas Refill', price: 3200 },
};
// Handle incoming WhatsApp messages via webhook
function handleOrder(phone, message) {
const msg = message.trim().toUpperCase();
// ORDER command: ORDER 1 M 2
if (msg.startsWith('ORDER')) {
const parts = msg.split(' ');
const itemId = parts[1];
const size = parts[2] || 'N/A';
const qty = parseInt(parts[3]) || 1;
const product = products[itemId];
if (!product) return sendMsg(phone, '\u274c Item not found. Check catalog.');
if (!carts[phone]) carts[phone] = [];
carts[phone].push({ ...product, size, qty });
sendMsg(phone,
`\u2705 *Added to cart!*\n\n` +
`${product.name} (${size}) x${qty}\n` +
`Subtotal: KES ${product.price * qty}\n\n` +
`Reply *CART* to view cart\nReply *INVOICE* for total`
);
}
// INVOICE command: Generate formatted invoice
if (msg === 'INVOICE' || msg === 'PAY') {
const cart = carts[phone];
if (!cart || cart.length === 0)
return sendMsg(phone, '\ud83d\uded2 Your cart is empty!');
let total = 0;
let invoice = '\ud83d\udcdd *INVOICE*\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n';
cart.forEach(item => {
const sub = item.price * item.qty;
invoice += `\u2022 ${item.name} (${item.size}) x${item.qty} \u2014 KES ${sub.toLocaleString()}\n`;
total += sub;
});
const delivery = 200;
invoice += `\n\ud83d\ude9a Delivery \u2014 KES ${delivery}`;
invoice += `\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`;
invoice += `\n*TOTAL: KES ${(total + delivery).toLocaleString()}*`;
invoice += `\n\n\ud83d\udcb3 *Pay via M-Pesa:*`;
invoice += `\nPaybill: XXXXXX`;
invoice += `\nAccount: ${phone}`;
invoice += `\n\n\u2705 Send M-Pesa screenshot to confirm!`;
sendMsg(phone, invoice);
}
}
async function sendMsg(to, message) {
await axios.post(`${BASE_URL}/api/messages/send`, {
clientId: CLIENT_ID, to, message
}, { headers: { 'x-api-key': API_KEY } });
}
π³ M-Pesa Payment Confirmation
After a customer pays, your system can listen for M-Pesa callbacks and automatically send confirmation:
// Auto-confirm payment and send dispatch notification
async function confirmPayment(phone, amount, mpesaCode) {
const message =
`\u2705 *PAYMENT CONFIRMED!*\n\n` +
`Amount: KES ${amount}\n` +
`M-Pesa Code: ${mpesaCode}\n\n` +
`\ud83d\udce6 Your order is being prepared!\n` +
`\ud83d\ude9a Estimated delivery: 2-4 hours\n\n` +
`Reply *TRACK* for live updates.`;
await axios.post(`${BASE_URL}/api/messages/send`, {
clientId: CLIENT_ID, to: phone, message
}, { headers: { 'x-api-key': API_KEY } });
}
π₯ Social Media & Content Creators
Use the Pewang Gateway to build a powerful WhatsApp presence for your social media brand. Here's what works, what's possible, and what's not β honestly.
β What WORKS Perfectly
β οΈ What's NOT Possible (Being Honest)
π΄ TikTok Live Blast β Code Example
When you go live on TikTok, instantly notify all your WhatsApp followers:
π‘ The Smart Approach: WhatsApp as Your Marketing Hub
Instead of trying to post TO social media from WhatsApp (which isn't technically possible), use WhatsApp as your central notification hub that drives traffic to all your platforms:
WhatsApp has 98% open rate vs. 2% on social media algorithms. Your message is guaranteed to be seen!