Understanding Webhooks and Their Implementation in .NET/C#

In the world of modern software, communication between systems is essential for seamless operation. One of the most efficient ways to handle this communication is through webhooks. Webhooks are widely used in event-driven workflows and provide real-time notifications between different systems. In this blog post, we will dive deep into what webhooks are, how they differ from REST APIs, and how to implement a simple webhook in an ASP.NET Core application.

What is a Webhook?

A webhook is a mechanism that allows one system to send real-time data or notifications to another system when a specific event or trigger occurs. Unlike traditional APIs, which rely on a request-response model, webhooks are event-driven, meaning that data is sent automatically once a specified event happens in the sending system.

For instance, when a new user signs up, a payment is made, or a file is uploaded, the sending system can trigger a webhook to notify the receiving system with relevant data. This eliminates the need for the receiving system to constantly poll or query the sending system for updates.

Webhooks vs. REST APIs: Key Differences

The core difference between a REST API and a webhook lies in how data is transferred and how events are triggered:

  • REST APIs operate on a request-response model, where the receiving system must request data from the server.
  • Webhooks are event-driven, meaning data is pushed from the sender to the receiver as soon as the event occurs.

Webhooks are often more efficient because they allow the sending system to automatically notify the receiving system, eliminating the need for continuous polling and making the process more real-time.

How Does a Webhook Work?

The process of setting up a webhook involves a few key steps:

  1. Event Occurrence: A specific event occurs in the sending system (e.g., new user signup, payment received).
  2. Payload Creation: The sending system generates a payload, which contains relevant event data (such as the user’s details or payment information).
  3. HTTP POST Request: The sending system then sends an HTTP POST request to the webhook endpoint in the receiving system. This endpoint is usually provided by the receiving system.
  4. Processing the Payload: The receiving system processes the incoming payload and takes the necessary actions. This could involve updating a database, triggering additional processes, or integrating with other services.

Why Use Webhooks?

Webhooks are particularly useful for real-time data exchange and event-driven workflows. For example, if your company uses a SaaS-based CRM system, you might want to be notified whenever a new client is added. By configuring a webhook, the CRM can automatically notify your system, allowing you to update your internal records or trigger further processes without manual intervention.

Moreover, webhooks are ideal for integrating disparate systems, as they can be used to communicate across different servers, applications, or even companies.

Implementing a Webhook in ASP.NET Core

Now that we understand the concept of webhooks, let’s walk through how to implement a simple webhook in an ASP.NET Core application.

1. Set Up the Project

First, create an empty ASP.NET Core application. You can do this via Visual Studio or by using the .NET CLI. Once the project is set up, we’ll configure the webhook endpoint to handle incoming POST requests.

2. Define the Webhook Endpoint

In the Program.cs file, add the following code to define a webhook endpoint using MapPost:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/webhook", async context =>
{
    var requestBody = await context.Request.ReadFromJsonAsync<WebhookPayload>();
    
    // Process the received webhook data
    Console.WriteLine($"Header: {requestBody?.Header}, Body: {requestBody?.Body}");

    context.Response.StatusCode = 200;
    await context.Response.WriteAsync("Webhook acknowledged");
});

app.Run();

In this code, we define a POST endpoint at /webhook. When an HTTP POST request is made to this URL, the payload is read and processed. For simplicity, we are just logging the payload data to the console.

3. Define the Payload

The payload is the data sent by the sender when the event occurs. To capture this data, create a simple WebhookPayload record:

public record WebhookPayload(string Header, string Body);

This record will hold the Header and Body of the incoming request, which are part of the data sent by the sender when the webhook is triggered.

4. Testing the Webhook

To test the webhook, you can use tools like Postman or cURL to send a POST request to the webhook endpoint. In Postman, set the request URL to http://localhost:7103/webhook, choose the POST method, and send a JSON body like this:

{
  "Header": "Test Header",
  "Body": "Hello, Webhook!"
}

When you send this request, you should see the following output in your console:

Header: Test Header, Body: Hello, Webhook!

Additionally, the response from the webhook will be "Webhook acknowledged", indicating that the webhook has been successfully received.

Adding Authentication to Your Webhook

For security purposes, it’s a good idea to add authentication to your webhook. A common approach is to use an API key or JWT for verifying that the request comes from a trusted source.

Here’s how you can add API key-based authentication to your webhook:

app.MapPost("/webhook", async context =>
{
    var apiKey = context.Request.Headers["Authorization"];
    if (apiKey != "your-api-key")
    {
        context.Response.StatusCode = 401;
        await context.Response.WriteAsync("Unauthorized");
        return;
    }

    var requestBody = await context.Request.ReadFromJsonAsync<WebhookPayload>();
    Console.WriteLine($"Header: {requestBody?.Header}, Body: {requestBody?.Body}");

    context.Response.StatusCode = 200;
    await context.Response.WriteAsync("Webhook acknowledged");
});

In this example, the API key is checked in the Authorization header of the incoming request. If the key doesn’t match, the server responds with a 401 Unauthorized status.

Conclusion

Webhooks are an excellent way to enable real-time, event-driven communication between different systems. By implementing a webhook in an ASP.NET Core application, you can easily receive notifications from other systems whenever a specified event occurs.

As shown in the example, integrating authentication and handling the webhook payload efficiently makes this a powerful tool for system integration and automation.

With the foundation of webhooks set up, you can extend this implementation to meet specific requirements. For example integrating with databases, triggering notifications, or updating internal systems based on the events received from external services.

By mastering webhooks, you can significantly improve the efficiency and responsiveness of your applications.

This entire exercise is available in my YouTube video here: https://youtu.be/fTvnM8roWjE?si=IcEiwXQWiCtD4qza