Have you ever wanted to receive notifications from a service in Discord, only to discover that it doesn’t support Discord webhooks?
Maybe it’s a self-hosted application, a monitoring tool, a CI/CD pipeline, or a service that only allows you to configure a generic HTTP webhook.
Discord has built-in webhook support, but there’s a catch: the incoming payload needs to be in a format Discord understands.
If the service sends a completely different JSON structure, you usually end up writing a small backend, a serverless function, or some custom glue code just to transform the payload.
I wanted to make that process easier.
So I built Send Any Webhook to Discord.
🔗 GitHub: https://github.com/bhumit070/send-anywebhook-to-discord
📖 Documentation: https://bhumit070.github.io/send-anywebhook-to-discord/
The Problem
Imagine you have a service that sends a webhook whenever a task is completed.
It sends a payload like this:
{
"event": "task.completed",
"data": {
"task": {
"id": 123,
"title": "Deploy production",
"status": "completed",
"duration": 42
}
}
}
Now, you want this notification to appear in Discord:
🚀 Task Completed
Deploy production
Status: Completed
Duration: 42 seconds
Discord doesn’t automatically know how to interpret your application’s custom JSON structure.
You could write a Node.js service to receive the webhook, parse the payload, construct a Discord message, and send it to the channel.
But what if you want to do this for multiple services?
What if you want to change the message format?
What if you want to inspect failed deliveries or replay an event?
That’s where a webhook relay becomes useful.
What is Send Any Webhook to Discord?
It’s an open-source, self-hosted application that receives webhooks from external services, transforms their payloads into Discord messages, and delivers them to your Discord channel.
Instead of building a custom integration for every service, you configure a relay once and reuse it.
The workflow looks like this:
External Service
|
| HTTP POST / JSON
v
Webhook Relay
|
| Validate & Queue
v
Template Renderer
|
| Discord Message
v
Discord Webhook
|
v
Discord Channel
The application provides a web UI where you can configure relays, map payload fields, preview messages, manage delivery logs, and troubleshoot failures.
And because it’s self-hosted, you control where it runs and how your webhook data is handled.
Features
- Accept Webhooks from Any Service
If a service can send an HTTP POST or PUT request with a JSON body, you can connect it.
Each relay gets its own unique endpoint.
For example:
https://your-domain.com/h/your-relay-key
You can configure the source service to send its webhook to this URL.
The relay accepts the payload and processes it asynchronously.
- Visual Payload Mapping
This is one of the features I wanted to make particularly easy to use.
You don’t have to manually write a template just to get started.
You can provide a sample JSON payload and map its fields to Discord message properties using a visual interface.
For example:
Discord Property Payload Field
Title data.task.title
Description data.task.status
Color A configured value
Embed Field data.task.duration
The Discord-style preview updates as you configure the message.
This makes it easier to understand how your webhook data will appear before sending an actual notification.
- JSON Schema Support
Don’t have a sample payload?
If the service provides a JSON Schema, you can paste it into the application to help generate a representative sample payload.
You can also capture the next incoming webhook and use that payload as your template input.
This is particularly useful when integrating with services that have complex or deeply nested payloads.
- Custom Templates with Liquid
For more advanced use cases, you can write templates directly using Liquid.
For example:
{
"embeds": [
{
"title": "{{ data.task.title }}",
"description": "Status: {{ data.task.status }}",
"color": 5814783
}
]
}
The application also provides additional filters and helpers for formatting values, working with booleans and numbers, and generating fields from arrays.
You can start with the visual mapper and move to custom templates whenever you need more control.
- Authentication Options
Not every webhook endpoint should be publicly accessible without protection.
Each relay can be configured with different authentication options:
- Secret header
- Username and password
- HMAC signature
- URL-only authentication
This allows you to choose an authentication method supported by the source service.
- Queued Delivery and Retries
Webhook processing happens asynchronously.
When a valid webhook arrives, it’s stored in the queue and the source receives a 202 Accepted response.
A background worker then:
- Retrieves the queued event.
- Finds the matching template.
- Renders the Discord message.
- Sends it to Discord.
- Records the delivery result.
If Discord returns a rate-limit response, the worker respects Discord’s retry_after value.
Temporary network failures and server errors are retried with backoff.
This means the incoming request doesn’t have to wait for Discord to respond.
- Delivery Logs and Replay
Debugging webhook integrations can be frustrating when you don’t know what happened to a particular event.
The application includes a logs interface where you can inspect delivery attempts and their results.
You can:
- Search and filter webhook events.
- Inspect received payloads.
- View delivery attempts and Discord responses.
- Retry failed deliveries.
- Replay previous events.
- Cancel queued events.
- Send events immediately.
- Process older events when there’s a backlog.
This is especially useful when you’re developing templates or troubleshooting an integration.
Built with TypeScript
I wanted the project to have a clean separation between the frontend, API, and delivery logic.
The main technologies are:
- Backend: Node.js, TypeScript, Fastify
- Frontend: React, Tailwind CSS, shadcn/ui
- Database: PostgreSQL
- ORM: Drizzle ORM
- Templating: Liquid
- Deployment: Docker Compose
One architectural detail worth mentioning is that the preview in the frontend and the actual delivery worker use the same renderer from the shared package.
That way, the message shown in the preview is rendered using the same logic as the message sent to Discord.
The project also includes automated tests, type checking, database migrations, and prebuilt Docker images published to GitHub Container Registry.
Getting Started
The easiest way to run it is with Docker Compose.
- Clone the Repository
git clone https://github.com/bhumit070/send-anywebhook-to-discord.git
cd send-anywebhook-to-discord
- Configure Environment Variables
cp .env.example .env
Set the required secrets in your .env file.
For example, generate an application secret:
openssl rand -hex 32
Use the generated value for APP_SECRET and configure your PostgreSQL password.
- Start the Application
docker compose up -d --build
Once the containers are running, you can access:
- Web UI: http://localhost:5252
- API Documentation: http://localhost:5252/docs
- Health Check: http://localhost:5252/healthz
The database migrations run automatically when the backend starts.
For public access, put the application behind HTTPS and configure PUBLIC_BASE_URL accordingly.
- Create Your First Relay
The basic workflow is:
- Create a relay and give it a name.
- Configure the Discord webhook URL.
- Provide a sample JSON payload or JSON Schema.
- Map the payload fields to a Discord message.
- Configure authentication.
- Copy the generated relay URL.
- Configure your source service to send webhooks to that URL.
That’s it.
Your service can now send webhook events to Discord without needing a custom integration for every payload format.
Who Is This For?
Some use cases I had in mind:
- Self-hosted applications that support generic webhooks.
- CI/CD pipelines that need deployment notifications.
- Monitoring and uptime services.
- Automation tools.
- Personal projects and homelab notifications.
- Applications that send custom JSON payloads.
- Developers who want to experiment with webhook integrations without writing glue code.
If you’re already running Docker-based services in your homelab, this can be another small service that connects your applications to Discord.
Why Self-Host?
I wanted this project to be something developers could run on their own infrastructure rather than depend on another hosted service.
Self-hosting gives you control over:
- Where webhook payloads are stored.
- How long delivery logs are retained.
- Which services can access your relay endpoints.
- How the application is deployed and maintained.
The project is released under the MIT license, so you’re free to use, modify, and contribute to it.
What’s Next?
There are plenty of directions this project could go.
I’d love to hear how people are using it and what integrations or features would make it more useful.
If you have a service that sends webhooks but doesn’t support Discord, give it a try.
And if you find a bug, have an idea, or want to contribute, feel free to open an issue or pull request.
Try It Out
🔗 GitHub: https://github.com/bhumit070/send-anywebhook-to-discord
📖 Documentation: https://bhumit070.github.io/send-anywebhook-to-discord/
⭐ If you find it useful, consider giving the repository a star.
Feedback and contributions are always welcome!
Top comments (0)