A sample project demonstrating the webhook pattern between a C# .NET 10 Minimal API with SignalR and a React + TypeScript frontend, fully containerized with Docker Compose.
WebhookExample/
βββ docker-compose.yml
βββ api/
β βββ Dockerfile
β βββ WebhookApi.csproj (.NET 10)
β βββ Program.cs Minimal API + SignalR
β βββ Models/
β β βββ WebhookEvent.cs
β β βββ WebhookListener.cs
β βββ Hubs/
β βββ WebhookHub.cs
βββ frontend/
βββ Dockerfile
βββ nginx.conf
βββ package.json
βββ vite.config.ts
βββ src/
βββ App.tsx Tabs + SignalR connection
βββ index.css
βββ types/webhook.ts
βββ services/webhookService.ts
βββ components/
βββ EventLog.tsx Real-time event log
βββ SendWebhook.tsx Send webhook form
βββ Listeners.tsx Listener CRUD
| Method | Route | Description |
|---|---|---|
POST |
/api/webhooks/receive |
Receives a webhook, stores it and forwards it to all listeners |
GET |
/api/webhooks/events |
Returns the last 100 events |
DELETE |
/api/webhooks/events |
Clears all events |
POST |
/api/webhooks/send |
Sends a webhook to any URL |
POST |
/api/webhooks/listeners |
Registers a listener |
GET |
/api/webhooks/listeners |
Lists all listeners |
DELETE |
/api/webhooks/listeners/{id} |
Removes a listener |
PATCH |
/api/webhooks/listeners/{id}/toggle |
Toggles a listener on/off |
| Hub | /webhookHub |
SignalR hub for real-time updates |
docker compose up --build- Frontend: http://localhost:3000
- API: http://localhost:5000
API:
cd api
dotnet runFrontend:
cd frontend
npm install
npm run devThe Vite dev server proxies requests to
http://localhost:5000, so no additional CORS configuration is needed during development.
- Open http://localhost:3000
- From the Send tab, fire a webhook to
http://localhost:5000/api/webhooks/receive - The event appears in real time in the Events tab via SignalR
- Register an external URL in the Listeners tab (e.g. https://webhook.site) β every incoming webhook will be automatically forwarded to it
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Docker Compose (network: webhook-net) β
β β
β ββββββββββββββββββββ βββββββββββββββββββββββββββββ β
β β frontend :3000 β β api :5000 β β
β β (nginx) β β (.NET 10 Minimal API) β β
β β β β β β
β β React + TS βββHTTPβββΆ POST /receive β β
β β (Vite build) β β GET /events β β
β β βββWSβββββ SignalR /webhookHub β β
β ββββββββββββββββββββ β β β
β β² β Forwards to listeners βββΆβ β
β β proxy βββββββββββββββββββββββββββββ β
β localhost:3000 β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- SignalR β The API pushes real-time notifications to the frontend whenever a webhook is received (
WebhookReceived) or events are cleared (EventsCleared). - Listeners β Registered URLs that automatically receive an HTTP POST copy of every incoming webhook.
- In-memory storage β Events and listeners are stored in memory (
ConcurrentQueue/ConcurrentDictionary). Data is lost when the container restarts.
| Variable | Default | Description |
|---|---|---|
ASPNETCORE_URLS |
http://+:5000 |
Listening port |
ASPNETCORE_ENVIRONMENT |
Development |
Runtime environment |
