What is a Webhook?
A webhook is like a notification system between two applications.
When something happens in one system (like a new record is created), it sends a small message (HTTP POST) to another system’s URL to tell it, “Hey, something just happened!”
You don’t need to constantly check for updates — you just get notified instantly.
Example
If a new item is added to a SharePoint list, SharePoint can call your Azure Function and send the item details.
Your Azure Function can then:
Why Use Azure Functions for Webhooks?
Azure Functions are perfect for receiving webhooks because they:
- Run in the cloud (no servers to manage) 
- Automatically scale 
- Are cheap — you only pay when they run 
- Easily integrate with other Azure services 
Basically, Azure Functions are the easiest way to create a public API endpoint that reacts to webhook events.
How Webhooks Work?
- Register: The source system (like SharePoint) is told where to send notifications (your Azure Function URL). 
- Validation: The source might send a “challenge” request to confirm your URL works. Your function must respond correctly. 
- Event Happens: When an event occurs, the source sends data to your URL via an HTTP POST. 
- Process: Your Azure Function reads the data and does something useful (save to DB, trigger another service, etc.). 
Creating a Webhook Receiver in .NET 9
Let’s build a webhook receiver using Azure Functions (.NET 9, isolated worker model).
Step 1. Create a New Azure Function Project
- Open Visual Studio 
Launch Visual Studio → click Create a new project.
- Choose Project Template 
Search for “Azure Functions” in the templates list.
Select
Azure Functions → Click Next
- Configure the Project 
- Project Name: - WebhookReceiver
 
- Location: Choose any local folder 
- Framework: Choose .NET 9.0 (Isolated) 
- Click Create 
- Configure Function Settings 
Visual Studio will now ask for more setup options:
| Setting | Value | 
|---|
| Functions Worker | .NET Isolated | 
| Function Template | HTTP trigger | 
| Authorization level | Function | 
| Storage Account | (Storage emulator or None for now) | 
- Click Create 
Step 2. Add Required Packages
Make sure your .csproj looks like this:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.*" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.*" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.*" />
  </ItemGroup>
</Project>
Step 3. Program.cs (App Setup)
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services =>
    {
        services.AddHttpClient();
    })
    .ConfigureLogging(logging => logging.AddConsole())
    .Build();
await host.RunAsync();
Step 4. Write the Function Code
Create a file called WebhookHandler.cs.
using System.Net;
using System.Text.Json;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
public class WebhookHandler
{
    private readonly ILogger _logger;
    public WebhookHandler(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<WebhookHandler>();
    }
    [Function("WebhookReceiver")]
    public async Task<HttpResponseData> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
    {
        _logger.LogInformation("Webhook request received.");
        // Step 1: Handle validation (for example, SharePoint challenge)
        if (req.Url.Query.Contains("validationtoken"))
        {
            var query = System.Web.HttpUtility.ParseQueryString(req.Url.Query);
            var token = query["validationtoken"];
            var response = req.CreateResponse(HttpStatusCode.OK);
            await response.WriteStringAsync(token ?? "");
            return response;
        }
        // Step 2: Read the POST body
        var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        _logger.LogInformation("Payload received: {body}", requestBody);
        // Step 3: Deserialize the JSON
        var data = JsonSerializer.Deserialize<WebhookPayload>(requestBody);
        if (data == null)
        {
            var badResponse = req.CreateResponse(HttpStatusCode.BadRequest);
            await badResponse.WriteStringAsync("Invalid payload");
            return badResponse;
        }
        // Step 4: Do your business logic here
        _logger.LogInformation("Processing event: {event}", data.EventName);
        // Step 5: Return success
        var okResponse = req.CreateResponse(HttpStatusCode.OK);
        await okResponse.WriteStringAsync("Webhook processed successfully");
        return okResponse;
    }
}
public class WebhookPayload
{
    public string EventName { get; set; }
    public string ResourceId { get; set; }
}
Step 5. Secure the Function
To keep it safe, use a secret header.
Add this check before processing the payload:
if (!req.Headers.TryGetValues("x-webhook-secret", out var secrets) ||
    secrets.FirstOrDefault() != Environment.GetEnvironmentVariable("WEBHOOK_SECRET"))
{
    _logger.LogWarning("Unauthorized request!");
    var unauthorized = req.CreateResponse(HttpStatusCode.Unauthorized);
    await unauthorized.WriteStringAsync("Unauthorized");
    return unauthorized;
}
Add this to your local.settings.json:
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "WEBHOOK_SECRET": "my-super-secret-key"
  }
}
Step 6. Test Locally
Run your app:
func start
Then use Postman to send:
{
  "EventName": "ItemCreated",
  "ResourceId": "12345"
}
You should see a success message in the console.
We will see the deployment to Azure in next article.
Conclusion
Webhooks and Azure Functions are a powerful combination.
They help you create fast, event-driven solutions that respond in real time — without servers or complex infrastructure.
With just a few lines of code in .NET 9, you can build a scalable webhook receiver that integrates with SharePoint, Power Apps, or any external service.