Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

Testing M-PESA STK Push Callbacks Locally Without Exposing Your Server

If you've ever built an M-PESA STK Push integration, you've probably hit this wall: M-PESA needs a publicly accessible callback URL to send payment confirmations, but your app is running on localhost. How do you test this without deploying…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

If you've ever built an M-PESA STK Push integration, you've probably hit this wall: M-PESA needs a publicly accessible callback URL to send payment confirmations, but your app is running on localhost. How do you test this without deploying every single time?



In this guide I'll show you a simple approach using webhook.site and a small Node.js poller script that automatically forwards M-PESA callbacks to your local machine.









What We're Building



When a user completes an STK Push payment, M-PESA sends a POST request to your callback URL with the payment result. Normally that URL has to be publicly accessible. Since localhost isn't public, we'll use webhook.site as a middleman - it catches the callback from M-PESA, and our poller script picks it up and forwards it to our local app automatically.



The flow looks like this:



M-PESA → webhook.site → our poller script → localhost









Prerequisites




  • Node.js installed on your machine

  • Your Laravel app running locally

  • An M-PESA Daraja API account (sandbox or production)

  • Basic understanding of how STK Push works









Step 1 - Get a webhook.site URL



Go to webhook.site and you'll immediately get a unique URL that looks like this:




https://webhook.site/f5d500b7-1196-42ef-8ecd-c906e49f7df36






The part after the last slash is your token. Copy it - you'll need it shortly. Keep this tab open so you can see incoming requests.









Step 2 - Store the Callback URL in Your .env



Instead of hardcoding the webhook.site URL in your code, store it in your .env file so you can swap it out easily without touching any code:




MPESA_CALLBACK_URL=https://webhook.site/f5d500b7-1196-42ef-8ecd-c906e49f7df36






On production you simply leave this variable out and it falls back to your real callback URL automatically.









Step 3 - Update Your ProcessController



In your M-PESA ProcessController where you build the STK Push request, find the CallBackURL line and update it like this:




"CallBackURL" => env('MPESA_CALLBACK_URL') ?: route('ipn.MPesa'),






What this does is simple. If MPESA_CALLBACK_URL is set in your .env it uses that. If it's not set, it falls back to your real route. This means locally it points to webhook.site, and on production it uses your actual callback route - no code changes needed when you deploy.









Step 4 - Create the Poller Script



This is the magic piece. Create a file called forwarder.js anywhere on your machine - I put mine in the project root. Paste this in:




const WEBHOOK_TOKEN = 'f5d500b7-1196-42ef-8ecd-c906e49f7df36'; // your token here
const LOCAL_URL = 'http://localhost:8000/ipn/mpesa';
const POLL_INTERVAL = 5000; // check every 5 seconds

let lastSeenId = null;

async function poll() {
try {
const res = await fetch(`https://webhook.site/token/${WEBHOOK_TOKEN}/requests?sorting=newest&per_page=1`);
const data = await res.json();

if (!data.data || data.data.length === 0) return;

const latest = data.data[0];

if (latest.uuid === lastSeenId) return; // already processed this one

lastSeenId = latest.uuid;

const body = latest.content;
console.log('New callback received! Forwarding to local app...');
console.log(body);

const forward = await fetch(LOCAL_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: body
});

console.log('Done. Local app responded with status:', forward.status);

} catch (err) {
console.error('Error:', err.message);
}
}

setInterval(poll, POLL_INTERVAL);
console.log('Watching webhook.site for incoming callbacks...');






Replace the WEBHOOK_TOKEN value with your own token from Step 1. The LOCAL_URL should match whatever route your app uses for the M-PESA IPN.









Step 5 - Run Everything



You'll need two terminals open.



Terminal 1 - start your Laravel app:




php artisan serve






Terminal 2 - start the poller:




node forwarder.js






You should see this message in Terminal 2:




Watching webhook.site for incoming callbacks...












Step 6 - Trigger a Test Payment



Go through your app's deposit flow and trigger an STK Push. Enter your phone number and hit pay. You'll get the prompt on your phone.



Once you complete the payment, here's what happens automatically:




  1. M-PESA sends the callback to webhook.site

  2. Your poller picks it up within 5 seconds

  3. It forwards the full payload to your local app

  4. Your local app processes it and updates the database



You'll see something like this in Terminal 2:




New callback received! Forwarding to local app...
{"Body":{"stkCallback":{"ResultCode":0,"CheckoutRequestID":"ws_CO_xxxxx",...}}}
Done. Local app responded with status: 200






And your database gets updated just like it would in production.









Why Not Just Use ngrok?



Ngrok is the most common answer to this problem and it works well. However if you're running a licensed script, adding a new public URL can trigger a second domain detection and invalidate your license. The webhook.site approach avoids this completely since your app never gets a new public URL - only the callback endpoint changes temporarily, and only in your local .env.









Cleaning Up After Testing



When you're done testing, remove MPESA_CALLBACK_URL from your .env or comment it out:




# MPESA_CALLBACK_URL=https://webhook.site/f5d500b7-1196-42ef-8ecd-c906e49f7df36






Your app will fall back to the real route automatically. Stop the forwarder.js script and you're done. Nothing was changed in your codebase, nothing gets pushed to production.









Summary



The whole setup takes about 5 minutes and gives you a proper local testing loop for M-PESA callbacks without ngrok, without deploying, and without touching your production environment. The poller script is lightweight, requires no dependencies beyond Node.js, and you can reuse the same approach for any other payment gateway callback - just change the LOCAL_URL to point to the right IPN route.

1. Sofort-Triage & Abwehrmaßnahmen

SOC Incident Playbook: Vulnerability Remediation & Verification
Syntax validiert (0 Fehler)
title: Detect Exploitation - Testing M-PESA STK Push Callbacks Locally Without Exposing Your Server
id: fb9752eb-50f1-4801-a354-0525c159515b
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-26
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-26"
        description = "YARA Signature for "
    strings:
        $str = "Testing M-PESA STK Push Callba" ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("Testing M-PESA STK Push Callbacks Locall")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*Testing M-PESA STK Push Callbacks Locall*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "Testing M-PESA STK Push Callbacks Locall"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc

2. Cyber Threat Intelligence & Forensik

🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich Testing M-PESA STK Push Callbacks Locall.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Testing M-PESA STK Push Callbacks Locally Without Exposing Your Server

Thematisch verwandte Begriffe: Testing, MPESA, Push, Callbacks · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-100534 | OpenClaw versions before 2026.8.1 contain an authorization bypass vulne…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag