.NET Webhook Receiver Guide

This section of Ottu Webhook Receivers Integration Guide focuses on .NET technologies, providing developers with practical examples and clear guidance for integrating Ottu webhook notifications into .NET applications. Our objective is to enable effective setup and management of webhook events.

Necessary data models and entity configurations for managing and storing webhook notifications and associated data in a .NET application are detailed here. The primary goal is to ensure the efficient capture of data pertaining to webhook notifications and the Checkout API Responses.

We require two main models: Checkout and Webhook.

  • The Checkout model:

    is designed to store details of the checkout process, including the session ID that uniquely identifies each payment transaction.

  • The Webhook model:

    It is structured to capture and store data from webhook notifications.

The Checkout model represents the data structure for storing information received from the Checkout API response. Here’s how you can define this model and configure its entities in .NET:

Model Definition:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;

namespace YourNamespace.Models
{
    public class Checkout
    {
        [Key]
        [Required]
        [StringLength(100)]
        public string SessionId { get; set; }

        [Required]
        [StringLength(250)]
        public string Type { get; set; }

        [Required]
        [StringLength(250)]
        public string PaymentType { get; set; }

        [Required]
        [StringLength(20)]
        public string Amount { get; set; }

        [Required]
        [StringLength(10)]
        public string CurrencyCode { get; set; }

        [Required]
        [StringLength(250)]
        public string State { get; set; }

        [StringLength(250)]
        public string CustomerId { get; set; }

        [StringLength(250)]
        public string Token { get; set; }

        [Column(TypeName = "jsonb")]
        public JsonDocument Agreement { get; set; }

        [Column(TypeName = "jsonb")]
        public JsonDocument ExtraParams { get; set; }

        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    }
}

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;
using System.Linq;

namespace YourNamespace.Models
{
    public class Webhook
    {
        [Key]
        public int Id { get; set; }

        [Required]
        [StringLength(250)]
        public string SessionId { get; set; }

        [ForeignKey("Checkout")]
        public string CheckoutSessionId { get; set; }

        public Checkout Checkout { get; set; }

        [Column(TypeName = "jsonb")]
        public JsonDocument Payload { get; set; }

        public DateTime Timestamp { get; set; } = DateTime.UtcNow;

        public static Webhook CreateFromWebhook(string sessionId, JsonDocument payload, ApplicationDbContext context)
        {
            var checkout = context.Checkouts.FirstOrDefault(c => c.SessionId == sessionId);
            var webhook = new Webhook
            {
                SessionId = sessionId,
                Payload = payload,
                CheckoutSessionId = sessionId,  // Ensuring the foreign key is properly assigned
                Checkout = checkout
            };

            context.Webhooks.Add(webhook);
            context.SaveChanges();

            // Potential business logic for updating checkout details can be implemented here
            return webhook;
        }
    }
}

A new Controller should be created in your .NET project. This can be accomplished manually or by utilizing scaffolding tools in Visual Studio or the .NET CLI.

Here’s an example of how the WebhookController could look:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Text.Json;
using YourNamespace.Models;
using System.Linq;
using Microsoft.Extensions.Logging;

namespace YourNamespace.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WebhookController : ControllerBase
    {
        private readonly ILogger<WebhookController> _logger;
        private readonly ApplicationDbContext _context;

        public WebhookController(ILogger<WebhookController> logger, ApplicationDbContext context)
        {
            _logger = logger;
            _context = context;
        }

        [HttpPost]
        public IActionResult ReceiveWebhook([FromBody] JsonElement payload)
        {
            _logger.LogInformation("Webhook received: {Payload}", payload.GetRawText());

            if (!VerifySignature(payload))
            {
                return StatusCode(401, new { detail = "Unable to verify signature" });
            }

            try
            {
                var processedData = ProcessData(payload);
                var savedWebhook = SaveData(processedData);
                return Ok(new { detail = "Success", webhookId = savedWebhook.Id });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to process webhook");
                return StatusCode(400, new { detail = "Failed to process webhook" });
            }
        }

        private bool VerifySignature(JsonElement payload)
        {
            // Assume `CheckSignature` is an actual implementation method
            // Example implementation might look for a computed hash of the payload and compare it against a signature in the header
            var signature = HttpContext.Request.Headers["Signature"].FirstOrDefault();
            // Placeholder for actual implementation:
            return CheckSignature(payload.GetRawText(), signature, _context.WebhookKey);
        }

        private Webhook ProcessData(JsonElement payload)
        {
            // Assuming that the payload structure is known and matches the dictionary key names
            var data = JsonSerializer.Deserialize<Dictionary<string, string>>(payload.GetRawText());
            var sessionId = data["session_id"];
            return Webhook.CreateFromWebhook(sessionId, payload, _context);
        }

        private Webhook SaveData(Webhook webhook)
        {
            _context.Webhooks.Add(webhook);
            _context.SaveChanges();
            return webhook;
        }
    }
}

Key Points:

  1. Signature Verification:

    • It's crucial to verify the incoming webhook’s signature securely to ensure the data's integrity and authenticity. The signature verification logic should adhere to the method outlined in Ottu’s official documentation, available here.

  2. Data Processing:

    • The controller deserializes the JSON payload and processes it according to predefined business rules. The ProcessData method is tailored to manage the specific structure of the webhook data.

  3. Data Storage:

    • Once processed, the data is stored in the database using the SaveData method, typically through Entity Framework or another ORM.

  4. Logging:

    • Logging is essential for debugging and tracking webhook activity. It is important to log both the reception of data and any errors that occur.

Conclusion:

The foundational code detailed above establishes a solid starting point for developing a webhook receiver within a .NET environment. To further enhance integration and ensure effective operation, consider adopting the above Key Points with following best practices:

  • Response Status Codes: It is essential to meticulously manage the response status codes returned to Ottu, ensuring clear communication regarding the success or failure of the webhook handling.

  • Understanding Endpoint Requirements: Comprehensive knowledge of all endpoint requirements is essential for full compliance with Ottu's operational standards. Detailed information is available on our Endpoint Requirements page.

This guide is specifically designed to provide you with the necessary tools to set up a robust and streamlined webhook receiver. By following these industry best practices, you can manage webhook notifications with precision and security, ensuring that your integration is both effective and compliant.

Last updated