Local WhatsApp is a small development-only inbox and webhook simulator for apps that integrate with WhatsApp through Azure Communication Services-style webhook events.
It is intentionally not a replacement for Meta, Twilio, or ACS. It gives local compose stacks a deterministic place to capture outbound WhatsApp sends, inspect payloads in a browser, trigger delivery/read/failed callbacks, and inject inbound message webhooks without real phone numbers or provider credentials.
docker run --rm -p 8080:8080 \
-e WEBHOOK_URL='http://host.docker.internal:7214/api/webhooks/whatsapp?token=local-dev-token' \
ghcr.io/mileswright/local-whatsapp:latestOpen http://localhost:8080.
| Variable | Default | Purpose |
|---|---|---|
PORT |
8080 |
HTTP port inside the container. |
STORE_PATH |
/data/messages.json |
JSON persistence file. Set empty for in-memory mode. |
WEBHOOK_URL |
empty | App webhook endpoint. Receives Event Grid-shaped JSON arrays. |
AUTO_DELIVER |
true |
Automatically post a Delivered event after each outbound send. |
AUTO_DELIVER_DELAY_MS |
1500 |
Delay before the automatic delivery event. |
DEFAULT_FROM |
whatsapp:+15550001000 |
Sender shown on captured outbound messages. |
PUBLIC_BASE_URL |
empty | Optional URL shown in startup logs/config. |
curl -sS http://localhost:8080/api/messages \
-H 'content-type: application/json' \
-d '{"to":"+15551234567","body":"Hello from local dev"}'Response:
{
"id": "21d5f4f4-...",
"messageId": "fake-wa-21d5f4f4-...",
"status": "Sent",
"receipts": [
{
"to": "+15551234567",
"messageId": "fake-wa-21d5f4f4-..."
}
]
}curl -sS http://localhost:8080/api/messages/fake-wa-message-id/status \
-H 'content-type: application/json' \
-d '{"status":"Read"}'Supported statuses are Sent, Delivered, Read, and Failed.
curl -sS http://localhost:8080/api/inbound \
-H 'content-type: application/json' \
-d '{"from":"+15551234567","body":"I can start Monday."}'When WEBHOOK_URL is set, Local WhatsApp posts:
Microsoft.Communication.AdvancedMessageReceivedMicrosoft.Communication.AdvancedMessageDeliveryStatusUpdated
The payload shape matches the Event Grid array shape consumed by the TalentStorehouse local backend webhook.