A Node.js Express application that receives and handles webhooks from multiple services including Hugging Face and Vercel, sending rich embed notifications to Discord.
- Multi-service webhook support: Hugging Face, Vercel, and easily extensible for GitHub, Stripe, etc.
- Rich Discord notifications: Beautiful embed messages with timestamps, fields, and links
- Security: HMAC signature verification for Vercel and GitHub webhooks
- Organized structure: Modular routes, services, and utilities
- Request logging: Comprehensive logging for debugging and monitoring
- Health checks: Built-in endpoints for monitoring
- Easy deployment: Ready for Render, Railway, Vercel, or any Node.js hosting platform
webhook-hub/
โโโ app.js # Express application entry point
โโโ routes/
โ โโโ hf.js # Hugging Face webhook handler
โ โโโ vercel.js # Vercel webhook handler
โโโ services/
โ โโโ discord.js # Discord embed formatting and sending
โโโ utils/
โ โโโ verifySignature.js # HMAC signature verification
โโโ .env.example # Environment variables template
โโโ package.json # Dependencies and scripts
git clone https://github.com/HashimCodeDev/webhook-hub
cd webhook-hub
pnpm install
Copy the example environment file and configure it:
cp .env.example .env
Edit .env
with your Discord webhook URL:
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN
- Go to your Discord server
- Server Settings โ Integrations โ Webhooks
- Create New Webhook or use existing one
- Copy the Webhook URL
# Development mode
pnpm run dev
# Production mode
pnpm start
The server will start on http://localhost:3000
The webhook hub is deployed and available at: https://webhook-hub.onrender.com
- Local URL:
POST http://localhost:3000/webhook/huggingface
- Live URL:
POST https://webhook-hub.onrender.com/webhook/huggingface
- Purpose: Receives repository update notifications
- Discord Message: Rich embed with commit info, pusher, commit message, and repository details
- Local URL:
POST http://localhost:3000/webhook/vercel
- Live URL:
POST https://webhook-hub.onrender.com/webhook/vercel
- Purpose: Receives deployment status notifications
- Discord Message: Rich embed with deployment status, project info, and deployment URL
- Security: Optional HMAC signature verification
- Local URL:
POST http://localhost:3000/webhook/test
- Live URL:
POST https://webhook-hub.onrender.com/webhook/test
- Purpose: Testing and debugging webhook payloads
Local testing:
curl -X POST http://localhost:3000/webhook/huggingface \
-H "Content-Type: application/json" \
-d '{
"event": {
"action": "update",
"scope": "repo.content"
},
"repo": {
"type": "model",
"name": "my-awesome-model",
"url": {
"web": "https://huggingface.co/username/my-awesome-model"
},
"headSha": "c379e821c9c95d613899e8c4343e4bfee2b0c600"
},
"updatedRefs": [
{
"ref": "refs/heads/main",
"oldSha": "ce9a4674fa833a68d5a73ec355f0ea95eedd60b7",
"newSha": "c379e821c9c95d613899e8c4343e4bfee2b0c600"
}
]
}'
Live deployment testing:
curl -X POST https://webhook-hub.onrender.com/webhook/huggingface \
-H "Content-Type: application/json" \
-d '{
"event": {
"action": "update",
"scope": "repo.content"
},
"repo": {
"type": "model",
"name": "my-awesome-model",
"url": {
"web": "https://huggingface.co/username/my-awesome-model"
},
"headSha": "c379e821c9c95d613899e8c4343e4bfee2b0c600"
},
"updatedRefs": [
{
"ref": "refs/heads/main",
"oldSha": "ce9a4674fa833a68d5a73ec355f0ea95eedd60b7",
"newSha": "c379e821c9c95d613899e8c4343e4bfee2b0c600"
}
]
}'
Local testing:
curl -X POST http://localhost:3000/webhook/vercel \
-H "Content-Type: application/json" \
-d '{
"type": "deployment.succeeded",
"deployment": {
"id": "dpl_123456",
"url": "my-app-abc123.vercel.app",
"state": "READY",
"target": "production",
"meta": {
"githubCommitSha": "abc123def456"
}
},
"project": {
"name": "my-awesome-app"
}
}'
Live deployment testing:
curl -X POST https://webhook-hub.onrender.com/webhook/vercel \
-H "Content-Type: application/json" \
-d '{
"type": "deployment.succeeded",
"deployment": {
"id": "dpl_123456",
"url": "my-app-abc123.vercel.app",
"state": "READY",
"target": "production",
"meta": {
"githubCommitSha": "abc123def456"
}
},
"project": {
"name": "my-awesome-app"
}
}'
You can also test using Postman. Here are the request configurations:
Local testing:
- Method: POST
- URL:
http://localhost:3000/webhook/huggingface
- Headers:
Content-Type: application/json
- Body (raw JSON): Use the JSON from the cURL example above
Live deployment testing:
- Method: POST
- URL:
https://webhook-hub.onrender.com/webhook/huggingface
- Headers:
Content-Type: application/json
- Body (raw JSON): Use the JSON from the cURL example above
Local testing:
- Method: POST
- URL:
http://localhost:3000/webhook/vercel
- Headers:
Content-Type: application/json
- Body (raw JSON): Use the JSON from the cURL example above
Live deployment testing:
- Method: POST
- URL:
https://webhook-hub.onrender.com/webhook/vercel
- Headers:
Content-Type: application/json
- Body (raw JSON): Use the JSON from the cURL example above
Variable | Required | Description |
---|---|---|
DISCORD_WEBHOOK_URL |
โ Yes | Discord webhook URL for notifications |
VERCEL_WEBHOOK_SECRET |
โ No | Secret for Vercel webhook signature verification |
GITHUB_WEBHOOK_SECRET |
โ No | Secret for GitHub webhook signature verification |
PORT |
โ No | Server port (default: 3000) |
NODE_ENV |
โ No | Environment mode (development/production) |
ALLOWED_ORIGINS |
โ No | CORS allowed origins (comma-separated) |
For production deployments, enable signature verification:
- Vercel: In your project settings, add a webhook with a secret
- GitHub: In repository settings, add a webhook with a secret
- Set the corresponding environment variables in your deployment platform
- Connect your GitHub repository to Render
- Create a new Web Service
- Set build command:
pnpm install
- Set start command:
pnpm start
- Add environment variables in Render dashboard
- Connect your GitHub repository to Railway
- Railway will auto-detect the Node.js app
- Add environment variables in Railway dashboard
- Deploy automatically on git push
- Install Vercel CLI:
npm i -g vercel
- Run
vercel
in project directory - Add environment variables via Vercel dashboard
- Note: Vercel has serverless limitations for webhook receivers
The application is designed for easy extension. To add a new provider (e.g., GitHub, Stripe):
// routes/github.js
import express from "express";
import { sendDiscordEmbed, createGenericEmbed } from "../services/discord.js";
const router = express.Router();
router.post("/", async (req, res) => {
// Handle GitHub webhook logic
const embed = createGenericEmbed({
title: "๐ GitHub Event",
description: "Repository activity detected",
color: 0x24292e,
});
await sendDiscordEmbed(process.env.DISCORD_WEBHOOK_URL, embed);
res.json({ success: true });
});
export default router;
import githubRoutes from "./routes/github.js";
app.use("/webhook/github", githubRoutes);
Use the utilities in utils/verifySignature.js
for HMAC verification.
-
Discord messages not sending
- Check
DISCORD_WEBHOOK_URL
is correctly set - Verify the webhook URL is valid and active
- Check server logs for error messages
- Check
-
Signature verification failing
- Ensure webhook secrets match between service and environment variables
- Check that raw body is being captured correctly
- Verify the signature format matches the service's specification
-
Port already in use
- Change the
PORT
environment variable - Kill existing processes:
pkill -f node
- Change the
Set NODE_ENV=development
for detailed error messages and request logging.
This project is licensed under the ISC License - see the LICENSE file for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature
- Commit your changes:
git commit -m 'Add amazing feature'
- Push to the branch:
git push origin feature/amazing-feature
- Open a Pull Request
If you encounter any issues or have questions:
- Check the troubleshooting section above
- Review the server logs for error messages
- Test with the
/webhook/test
endpoint first - Open an issue on GitHub with detailed information
Made with โค๏ธ for the developer community