Repository: Altinn/altinn-notifications
Pull request #851: Feature: Display the type of the notification order
Author: login: Ahmed-Ghanam
Created: 2025-05-15T12:42:59Z | Merged: 2025-05-20T14:46:23Z

## Description
Show the correct type, whether it is a notification or reminder, when retrieving tracking information for a specific shipment.

## Related Issue(s)
- #834 

## Verification
- [x] **Your** code builds clean without any errors or warnings
- [x] Manual testing done (required)
- [x] Relevant automated test added (if you find this hard, leave it and we'll help out)
- [x] All tests run green

## Documentation
- [ ] User documentation is updated with a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs) (if applicable)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced support for distinguishing notification orders by type (Notification or Reminder), visible in shipment tracking and order details.
  - Shipment tracking responses now include the notification type for each shipment.
- **Bug Fixes**
  - Improved error handling in shipment retrieval, returning structured error details for failed requests or client cancellations.
- **Refactor**
  - Enhanced internal handling and validation of notification order types throughout the system.
  - Refactored notification order chain registration to improve error propagation and contact information validation.
- **Database**
  - Added a new database column and enum for notification order type, with updated functions and procedures to support type-aware operations.
- **Tests**
  - Expanded and updated tests to ensure correct handling and validation of notification order types, including new scenarios for missing contact information and invalid order types.
  - Added tests verifying error responses for invalid notification order requests and missing SMS contact information.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/src/Altinn.Notifications.Core/Enums/OrderType.cs b/src/Altinn.Notifications.Core/Enums/OrderType.cs
new file mode 100644
index 000000000..1a0f5e7cf
--- /dev/null
+++ b/src/Altinn.Notifications.Core/Enums/OrderType.cs
@@ -0,0 +1,17 @@
+﻿namespace Altinn.Notifications.Core.Enums;
+
+/// <summary>
+/// Defines the different types of an order.
+/// </summary>
+public enum OrderType : uint
+{
+    /// <summary>
+    /// Represents a notification order that should be initiated immediately.
+    /// </summary>
+    Notification = 0,
+
+    /// <summary>
+    /// Represents a reminder order that should be initiated after the main order.
+    /// </summary>
+    Reminder = 1
+}
diff --git a/src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs b/src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs
index 6b4423db3..880398618 100644
--- a/src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs
+++ b/src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs
@@ -52,6 +52,11 @@ public interface IBaseNotificationOrder
     /// </summary>
     public SendingTimePolicy? SendingTimePolicy { get; }
 
+    /// <summary>
+    /// Gets the type of the notification order.
+    /// </summary>
+    public OrderType Type { get; }
+
     /// <summary>
     /// Gets or sets the condition endpoint used to check the send condition
     /// </summary>
diff --git a/src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs b/src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
index 699286ee7..d30fd3ca8 100644
--- a/src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
+++ b/src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
@@ -40,6 +40,9 @@ public class NotificationOrder : IBaseNotificationOrder
     /// <inheritdoc/>
     public SendingTimePolicy? SendingTimePolicy { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderType Type { get; internal set; }
+
     /// <summary>
     /// Gets the templates to create notifications based of
     /// </summary>
@@ -64,7 +67,8 @@ public NotificationOrder(
         List<Recipient> recipients,
         bool? ignoreReservation,
         string? resourceId,
-        Uri? conditionEndpoint)
+        Uri? conditionEndpoint,
+        OrderType type)
     {
         Id = id;
         SendersReference = sendersReference;
@@ -77,6 +81,7 @@ public NotificationOrder(
         IgnoreReservation = ignoreReservation;
         ResourceId = resourceId;
         ConditionEndpoint = conditionEndpoint;
+        Type = type;
     }
 
     /// <summary>
diff --git a/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs b/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs
index d300ec0c6..984ba5d2f 100644
--- a/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs
+++ b/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs
@@ -1,4 +1,5 @@
-﻿using Altinn.Notifications.Core.Models.Recipients;
+﻿using Altinn.Notifications.Core.Enums;
+using Altinn.Notifications.Core.Models.Recipients;
 
 namespace Altinn.Notifications.Core.Models.Orders;
 
@@ -95,12 +96,21 @@ private NotificationOrderChainRequest()
     /// </remarks>
     public string? SendersReference { get; private set; }
 
+    /// <summary>
+    /// Gets the type of the order.
+    /// </summary>
+    /// <remarks>
+    /// Specifies whether this is an initial notification or a reminder.
+    /// </remarks>
+    public OrderType Type { get; private set; }
+
     /// <summary>
     /// Builder class for <see cref="NotificationOrderChainRequest"/>.
     /// </summary>
     public class NotificationOrderChainRequestBuilder
     {
         private Guid _orderId;
+        private OrderType _type;
         private Guid _orderChainId;
         private Uri? _conditionEndpoint;
         private string? _sendersReference;
@@ -111,6 +121,17 @@ public class NotificationOrderChainRequestBuilder
         private DateTime _requestedSendTime = DateTime.UtcNow;
         private DialogportenIdentifiers? _dialogportenAssociation;
 
+        /// <summary>
+        /// Sets the type of the order.
+        /// </summary>
+        /// <param name="type">The order's type.</param>
+        /// <returns></returns>
+        public NotificationOrderChainRequestBuilder SetType(OrderType type)
+        {
+            _type = type;
+            return this;
+        }
+
         /// <summary>
         /// Sets the order identifier for the notification request.
         /// </summary>
@@ -216,6 +237,11 @@ public NotificationOrderChainRequest Build()
                 throw new InvalidOperationException("OrderChainId must be set.");
             }
 
+            if (_type != OrderType.Notification)
+            {
+                throw new InvalidOperationException("Invalid type used.");
+            }
+
             if (string.IsNullOrEmpty(_idempotencyId))
             {
                 throw new InvalidOperationException("IdempotencyId must be set.");
@@ -228,6 +254,7 @@ public NotificationOrderChainRequest Build()
 
             return new NotificationOrderChainRequest
             {
+                Type = _type,
                 OrderId = _orderId,
                 Creator = _creator,
                 Reminders = _reminders,
diff --git a/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs b/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs
index 2b0ae258e..ed0117a1d 100644
--- a/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs
+++ b/src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs
@@ -33,6 +33,9 @@ public class NotificationOrderWithStatus : IBaseNotificationOrder
     /// <inheritdoc/>>
     public string? ResourceId { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderType Type { get; internal set; }
+
     /// <inheritdoc/>>
     public Uri? ConditionEndpoint { get; set; }
 
@@ -64,7 +67,8 @@ public NotificationOrderWithStatus(
         bool? ignoreReservation,
         string? resourceId,
         Uri? conditionEndpoint,
-        ProcessingStatus processingStatus)
+        ProcessingStatus processingStatus, 
+        OrderType type)
     {
         Id = id;
         SendersReference = sendersReference;
@@ -76,6 +80,7 @@ public NotificationOrderWithStatus(
         ResourceId = resourceId;
         ConditionEndpoint = conditionEndpoint;
         ProcessingStatus = processingStatus;
+        Type = type;
     }
 
     /// <summary>
diff --git a/src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs b/src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs
index d382b27c0..82f7c87ea 100644
--- a/src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs
+++ b/src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs
@@ -1,4 +1,5 @@
-﻿using Altinn.Notifications.Core.Models.Recipients;
+﻿using Altinn.Notifications.Core.Enums;
+using Altinn.Notifications.Core.Models.Recipients;
 
 namespace Altinn.Notifications.Core.Models.Orders;
 
@@ -58,4 +59,12 @@ public class NotificationReminder
     /// A unique identifier used by the sender to correlate this reminder with their internal systems.
     /// </remarks>
     public string? SendersReference { get; set; }
+
+    /// <summary>
+    /// Gets the type of the reminder.
+    /// </summary>
+    /// <remarks>
+    /// Specifies that this is a reminder.
+    /// </remarks>
+    public OrderType Type { get; set; } = OrderType.Reminder;
 }
diff --git a/src/Altinn.Notifications.Core/Services/OrderRequestService.cs b/src/Altinn.Notifications.Core/Services/OrderRequestService.cs
index 4d68eb872..baf34f6e8 100644
--- a/src/Altinn.Notifications.Core/Services/OrderRequestService.cs
+++ b/src/Altinn.Notifications.Core/Services/OrderRequestService.cs
@@ -48,7 +48,7 @@ public OrderRequestService(
     public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(NotificationOrderRequest orderRequest)
     {
         Guid orderId = _guid.NewGuid();
-        DateTime currentime = _dateTime.UtcNow();
+        DateTime currentTime = _dateTime.UtcNow();
 
         var lookupResult = await GetRecipientLookupResult(orderRequest.Recipients, orderRequest.NotificationChannel, orderRequest.ResourceId);
 
@@ -59,10 +59,10 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
             Id = orderId,
             SendersReference = orderRequest.SendersReference,
             Templates = templates,
-            RequestedSendTime = orderRequest.RequestedSendTime ?? currentime,
+            RequestedSendTime = orderRequest.RequestedSendTime ?? currentTime,
             NotificationChannel = orderRequest.NotificationChannel,
             Creator = orderRequest.Creator,
-            Created = currentime,
+            Created = currentTime,
             Recipients = orderRequest.Recipients,
             IgnoreReservation = orderRequest.IgnoreReservation,
             ResourceId = orderRequest.ResourceId,
@@ -87,103 +87,73 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     /// <inheritdoc/>
     public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        Result<NotificationOrder, ServiceError> mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
-
-        if (mainOrder.IsError && mainOrder.Error != null)
+        // 3. Create the main order
+        var mainOrderResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainOrderResult.IsError && mainOrderResult.Error != null)
         {
-            return mainOrder.Error;
+            return mainOrderResult.Error;
         }
 
-        var reminderOrders = await CreateNotificationOrders(
-            orderRequest.Reminders,
-            orderRequest.Creator,
-            currentTime,
-            cancellationToken);
-
-        if (reminderOrders.IsError && reminderOrders.Error != null)
-        {
-            return reminderOrders.Error;
-        }
-
-        List<NotificationOrder> savedOrders = await _repository.Create(orderRequest, mainOrder.Value!, reminderOrders.Value, cancellationToken);
-
-        if (savedOrders == null || savedOrders.Count == 0)
+        // 4. Create reminders
+        var remindersResult = await CreateReminderNotificationOrdersAsync(orderRequest.Reminders, orderRequest.Creator, currentTime, cancellationToken);
+        if (remindersResult.IsError && remindersResult.Error != null)
         {
-            return new ServiceError(422, "Failed to create the notification order chain.");
+            return remindersResult.Error;
         }
 
-        // Get the main order (first in the list)
-        var savedMainOrder = savedOrders[0];
-
-        // Create and return the response
-        return new NotificationOrderChainResponse
-        {
-            OrderChainId = orderRequest.OrderChainId,
-            OrderChainReceipt = new NotificationOrderChainReceipt
-            {
-                ShipmentId = savedMainOrder.Id,
-                SendersReference = savedMainOrder.SendersReference,
-                Reminders = savedOrders.Count > 1
-                    ? [.. savedOrders
-                        .Where(e => e.Id != savedMainOrder.Id)
-                        .Select(order => new NotificationOrderChainShipment
-                        {
-                            ShipmentId = order.Id,
-                            SendersReference = order.SendersReference
-                        })]
-                    : null
-            }
-        };
+        // 5. Create the response
+        return await CreateChainResponseAsync(orderRequest, mainOrderResult.Value, remindersResult.Value, cancellationToken);
     }
 
     /// <summary>
-    /// Creates a new notification order using the specified recipient details and order parameters.
+    /// Creates the primary <see cref="NotificationOrder"/> for a notification chain by processing
+    /// recipient information, validating contact details, and configuring message templates.
     /// </summary>
-    /// <param name="recipient">
-    /// The <see cref="NotificationRecipient"/> that contains all necessary details for delivering the notification.
-    /// </param>
-    /// <param name="orderId">
-    /// A <see cref="Guid"/> that uniquely identifies the notification order.
-    /// </param>
-    /// <param name="sendersReference">
-    /// An optional reference identifier provided by the sender for correlating the order with external systems.
-    /// </param>
-    /// <param name="requestedSendTime">
-    /// The desired date and time for delivering the notification. If not specified, the current UTC date and time is used.
-    /// </param>
-    /// <param name="creator">
-    /// The creator information encapsulated in a <see cref="Creator"/> object that identifies who initiated the order.
+    /// <param name="orderRequest">
+    /// The incoming chain request containing recipient information, templates, and other notification parameters.
     /// </param>
     /// <param name="currentTime">
-    /// The current UTC date and time marking when the order is created.
+    /// The UTC timestamp to set as the creation time of the notification order.
     /// </param>
-    /// <param name="conditionEndpoint">
-    /// An optional <see cref="Uri"/> that serves as an endpoint to evaluate whether the notification should be sent.
+    /// <param name="cancellationToken">
+    /// A token that can be used to request cancellation of the asynchronous operation.
     /// </param>
     /// <returns>
-    /// On success a <see cref="Task{TResult}"/> containing a <see cref="NotificationOrder"/> returns the newly created notification order.
-    /// On failure, a <see cref="ServiceError"/> indicating the reason for failure.
+    /// A <see cref="Result{TValue,TError}"/> containing either:
+    /// <list type="bullet">
+    /// <item>
+    /// <description>A successful result with <see cref="Result{TValue,TError}.Value"/> containing the fully configured
+    /// <see cref="NotificationOrder"/> ready for persistence and processing</description>
+    /// </item>
+    /// <item>
+    /// <description>A failed result with <see cref="Result{TValue,TError}.Error"/> containing a
+    /// <see cref="ServiceError"/> with status code and detailed error message about the failure reason</description>
+    /// </item>
+    /// </list>
     /// </returns>
     /// <remarks>
-    /// This method extracts the delivery components (such as the recipient list, notification templates,
-    /// notification channel, reservation flag, and resource identifier) from the provided <paramref name="recipient"/>.
-    /// It performs a recipient lookup to ensure all necessary contact information exists.
-    /// Additionally, default sender information is applied to any templates that lack sender details.
+    /// This method performs recipient validation, template preparation, and order creation:
+    /// <list type="number">
+    /// <item><description>Extracts delivery components from the recipient configuration</description></item>
+    /// <item><description>Validates recipient contact information through lookup services</description></item>
+    /// <item><description>Applies default sender information where needed</description></item>
+    /// <item><description>Constructs a complete notification order with all required properties</description></item>
+    /// </list>
     /// </remarks>
-    private async Task<Result<NotificationOrder, ServiceError>> CreateNotificationOrder(NotificationRecipient recipient, Guid orderId, string? sendersReference, DateTime requestedSendTime, Creator creator, DateTime currentTime, Uri? conditionEndpoint)
+    /// <exception cref="OperationCanceledException">
+    /// Thrown when the operation is canceled through the provided <paramref name="cancellationToken"/>.
+    /// </exception>
+    private async Task<Result<NotificationOrder, ServiceError>> CreateMainNotificationOrderAsync(NotificationOrderChainRequest orderRequest, DateTime currentTime, CancellationToken cancellationToken)
     {
-        var (recipients, templates, channel, ignoreReservation, resourceId, sendingTimePolicyForSms) = ExtractDeliveryComponents(recipient);
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var (recipients, templates, channel, ignoreReservation, resourceId, sendingTimePolicyForSms) = ExtractDeliveryComponents(orderRequest.Recipient);
 
         var lookupResult = await GetRecipientLookupResult(recipients, channel, GetSanitizedResourceId(resourceId));
 
@@ -196,35 +166,196 @@ private async Task<Result<NotificationOrder, ServiceError>> CreateNotificationOr
 
         return new NotificationOrder
         {
-            Id = orderId,
-            SendersReference = sendersReference,
-            Templates = templates,
-            RequestedSendTime = requestedSendTime,
-            NotificationChannel = channel,
-            Creator = creator,
             Created = currentTime,
+            Templates = templates,
+            ResourceId = resourceId,
             Recipients = recipients,
+            Type = orderRequest.Type,
+            Id = orderRequest.OrderId,
+            NotificationChannel = channel,
+            Creator = orderRequest.Creator,
             IgnoreReservation = ignoreReservation,
-            ResourceId = resourceId,
-            ConditionEndpoint = conditionEndpoint,
-            SendingTimePolicy = sendingTimePolicyForSms
+            SendingTimePolicy = sendingTimePolicyForSms,
+            SendersReference = orderRequest.SendersReference,
+            RequestedSendTime = orderRequest.RequestedSendTime,
+            ConditionEndpoint = orderRequest.ConditionEndpoint
         };
     }
 
-    private static string? GetSanitizedResourceId(string? resourceId)
+    /// <summary>
+    /// Creates notification orders for each reminder in a list, validating contact information
+    /// for recipients and configuring message templates for each reminder.
+    /// </summary>
+    /// <param name="notificationReminders">
+    /// The list of notification reminders to process and convert into notification orders.
+    /// </param>
+    /// <param name="creator">
+    /// The identity of the entity that created the notification order chain.
+    /// </param>
+    /// <param name="currentTime">
+    /// The UTC timestamp to set as the creation time for all generated reminder orders.
+    /// </param>
+    /// <param name="cancellationToken">
+    /// A token that can be used to request cancellation of the asynchronous operation.
+    /// </param>
+    /// <returns>
+    /// A <see cref="Result{TValue,TError}"/> containing either:
+    /// <list type="bullet">
+    /// <item>
+    /// <description>A successful result with <see cref="Result{TValue,TError}.Value"/> containing a list of 
+    /// fully configured <see cref="NotificationOrder"/> objects ready for persistence</description>
+    /// </item>
+    /// <item>
+    /// <description>A failed result with <see cref="Result{TValue,TError}.Error"/> containing a
+    /// <see cref="ServiceError"/> with details about what went wrong during reminder processing</description>
+    /// </item>
+    /// </list>
+    /// </returns>
+    /// <remarks>
+    /// For each reminder, this method:
+    /// <list type="number">
+    /// <item><description>Extracts recipient contact details and notification channel preferences</description></item>
+    /// <item><description>Validates recipient contact information through lookup services</description></item>
+    /// <item><description>Applies default sender information where needed</description></item>
+    /// <item><description>Creates a properly configured notification order with creator metadata</description></item>
+    /// </list>
+    /// 
+    /// Processing stops at the first reminder that fails validation, returning the corresponding error.
+    /// If the input list is empty or null, an empty list is returned.
+    /// </remarks>
+    /// <exception cref="OperationCanceledException">
+    /// Thrown when the operation is canceled through the provided <paramref name="cancellationToken"/>.
+    /// </exception>
+    private async Task<Result<List<NotificationOrder>, ServiceError>> CreateReminderNotificationOrdersAsync(List<NotificationReminder>? notificationReminders, Creator creator, DateTime currentTime, CancellationToken cancellationToken)
     {
-        if (!string.IsNullOrWhiteSpace(resourceId))
+        var reminders = new List<NotificationOrder>();
+        if (notificationReminders is not { Count: > 0 })
         {
-            // Only perform replace if the prefix exists
-            if (resourceId.StartsWith("urn:altinn:resource:"))
+            return reminders;
+        }
+
+        foreach (var notificationReminder in notificationReminders)
+        {
+            cancellationToken.ThrowIfCancellationRequested();
+
+            var (recipients, templates, channel, ignoreReservation, resourceId, sendingTimePolicyForSms) = ExtractDeliveryComponents(notificationReminder.Recipient);
+
+            var lookupResult = await GetRecipientLookupResult(recipients, channel, GetSanitizedResourceId(resourceId));
+
+            if (lookupResult?.MissingContact?.Count > 0)
             {
-                return resourceId.Replace("urn:altinn:resource:", string.Empty);
+                return new ServiceError(422, $"Missing contact information for recipient(s): {string.Join(", ", lookupResult.MissingContact)}");
             }
 
-            return resourceId;
+            templates = SetSenderIfNotDefined(templates);
+
+            reminders.Add(new NotificationOrder
+            {
+                Creator = creator,
+                Templates = templates,
+                Created = currentTime,
+                Recipients = recipients,
+                ResourceId = resourceId,
+                NotificationChannel = channel,
+                Type = notificationReminder.Type,
+                Id = notificationReminder.OrderId,
+                IgnoreReservation = ignoreReservation,
+                SendingTimePolicy = sendingTimePolicyForSms,
+                SendersReference = notificationReminder.SendersReference,
+                RequestedSendTime = notificationReminder.RequestedSendTime,
+                ConditionEndpoint = notificationReminder.ConditionEndpoint
+            });
         }
 
-        return null;
+        return reminders;
+    }
+
+    /// <summary>
+    /// Persists a notification order chain and builds a response containing tracking information.
+    /// </summary>
+    /// <param name="orderRequest">
+    /// The original chain request containing configuration details and identifiers for the notification sequence.
+    /// </param>
+    /// <param name="mainOrder">
+    /// The primary notification order that should be persisted first and delivered immediately or at the requested time.
+    /// </param>
+    /// <param name="reminderOrders">
+    /// Optional collection of follow-up notification orders to be delivered after the main notification.
+    /// </param>
+    /// <param name="cancellationToken">
+    /// A token that can be used to request cancellation of the asynchronous database operation.
+    /// </param>
+    /// <returns>
+    /// A <see cref="Result{TValue,TError}"/> containing either:
+    /// <list type="bullet">
+    /// <item>
+    /// <description>A successful result with <see cref="Result{TValue,TError}.Value"/> containing a 
+    /// <see cref="NotificationOrderChainResponse"/> with the chain identifier and receipt information</description>
+    /// </item>
+    /// <item>
+    /// <description>A failed result with <see cref="Result{TValue,TError}.Error"/> containing a
+    /// <see cref="ServiceError"/> if persistence fails</description>
+    /// </item>
+    /// </list>
+    /// </returns>
+    /// <remarks>
+    /// This method:
+    /// <list type="number">
+    /// <item><description>Persists all orders in the chain as a single atomic transaction</description></item>
+    /// <item><description>Constructs a receipt containing identifiers for both main and reminder shipments</description></item>
+    /// <item><description>Returns a structured response that clients can use to track the notification chain</description></item>
+    /// </list>
+    /// </remarks>
+    /// <exception cref="OperationCanceledException">
+    /// Thrown when the operation is canceled through the provided <paramref name="cancellationToken"/>.
+    /// </exception>
+    private async Task<Result<NotificationOrderChainResponse, ServiceError>> CreateChainResponseAsync(NotificationOrderChainRequest orderRequest, NotificationOrder? mainOrder, List<NotificationOrder>? reminderOrders, CancellationToken cancellationToken)
+    {
+        var savedOrders = new List<NotificationOrder>();
+        if (mainOrder != null)
+        {
+            savedOrders = await _repository.Create(orderRequest, mainOrder, reminderOrders, cancellationToken);
+        }
+
+        if (savedOrders == null || savedOrders.Count == 0)
+        {
+            return new ServiceError(500, "Failed to create the notification order chain.");
+        }
+
+        // The first is the main shipment
+        var savedMain = savedOrders[0];
+
+        // Build response
+        var response = new NotificationOrderChainResponse
+        {
+            OrderChainId = orderRequest.OrderChainId,
+            OrderChainReceipt = new NotificationOrderChainReceipt
+            {
+                ShipmentId = savedMain.Id,
+                SendersReference = savedMain.SendersReference,
+                Reminders = savedOrders.Count > 1
+                    ? [.. savedOrders
+                        .Where(o => o.Id != savedMain.Id)
+                        .Select(o => new NotificationOrderChainShipment
+                        {
+                            ShipmentId = o.Id,
+                            SendersReference = o.SendersReference
+                        })]
+                    : null
+            }
+        };
+
+        return response;
+    }
+
+    private static string? GetSanitizedResourceId(string? resourceId)
+    {
+        if (string.IsNullOrWhiteSpace(resourceId))
+        {
+            return null;
+        }
+
+        return resourceId.StartsWith("urn:altinn:resource:", StringComparison.Ordinal) ? resourceId["urn:altinn:resource:".Length..] : resourceId;
     }
 
     private async Task<RecipientLookupResult?> GetRecipientLookupResult(List<Recipient> originalRecipients, NotificationChannel channel, string? resourceId)
@@ -392,64 +523,6 @@ private static SmsTemplate CreateSmsTemplate(SmsSendingOptions smsSettings)
         return new SmsTemplate(smsSettings.Sender, smsSettings.Body);
     }
 
-    /// <summary>
-    /// Creates notification orders for each reminder provided.
-    /// </summary>
-    /// <param name="reminders">
-    /// A list of <see cref="NotificationReminder"/> objects representing the reminders to be sent after the main notification order.
-    /// </param>
-    /// <param name="creator">
-    /// The <see cref="Creator"/> associated with the reminder orders, indicating the originator of the notifications.
-    /// </param>
-    /// <param name="currentTime">
-    /// The current UTC date and time, used as the reference time for creating the orders.
-    /// </param>
-    /// <param name="cancellationToken">
-    /// A token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.
-    /// </param>
-    /// <returns>
-    /// On success, a <see cref="Task{TResult}"/> containing a list of <see cref="List{NotificationOrder}"/> objects representing reminder orders.
-    /// On failure, a <see cref="ServiceError"/> indicating the reason for the failure.
-    /// </returns>
-    /// <remarks>
-    /// This method iterates through the provided reminders and, for each reminder, invokes 
-    /// <see cref="CreateNotificationOrder"/> to generate a corresponding reminder order using the reminder's details.
-    /// </remarks>
-    private async Task<Result<List<NotificationOrder>, ServiceError>> CreateNotificationOrders(List<NotificationReminder>? reminders, Creator creator, DateTime currentTime, CancellationToken cancellationToken = default)
-    {
-        var reminderOrders = new List<NotificationOrder>();
-
-        if (reminders == null || reminders.Count == 0)
-        {
-            return reminderOrders;
-        }
-
-        foreach (var reminder in reminders)
-        {
-            cancellationToken.ThrowIfCancellationRequested();
-
-            Result<NotificationOrder, ServiceError> result = await CreateNotificationOrder(
-                reminder.Recipient,
-                reminder.OrderId,
-                reminder.SendersReference,
-                reminder.RequestedSendTime,
-                creator,
-                currentTime,
-                reminder.ConditionEndpoint);
-
-            if (result.IsSuccess && result.Value != null)
-            {
-                reminderOrders.Add(result.Value);
-            }
-            else if (result.IsError && result.Error != null)
-            {
-                return result.Error;
-            }
-        }
-
-        return reminderOrders;
-    }
-
     /// <summary>
     /// Extracts information from a <see cref="NotificationRecipient"/> into notification delivery components.
     /// </summary>
diff --git a/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/getshipmenttracking.sql b/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/getshipmenttracking.sql
index 4b33bdba2..0b8aab136 100644
--- a/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/getshipmenttracking.sql
+++ b/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/getshipmenttracking.sql
@@ -73,3 +73,85 @@ Includes:
  - SMS notification tracking (status, result time, destination)
 
 If no matching order exists, an empty result set is returned.';
+
+
+-- This is a new version to return the type of the notification
+CREATE OR REPLACE FUNCTION notifications.get_shipment_tracking_v2(
+    _alternateid UUID,
+    _creatorname TEXT)
+RETURNS TABLE (
+    reference     TEXT,
+    status        TEXT,
+    last_update   TIMESTAMPTZ,
+    destination   TEXT,
+    type          TEXT
+) AS $$
+DECLARE
+    v_order_exists BOOLEAN;
+BEGIN
+    -- Check for the existence of the order
+    SELECT EXISTS (
+        SELECT 1
+        FROM notifications.orders o
+        WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname
+    )
+    INTO v_order_exists;
+
+    -- Return empty set if no order is found
+    IF NOT v_order_exists THEN
+        RETURN;
+    END IF;
+
+    -- Return combined tracking info
+    RETURN QUERY
+    WITH order_data AS (
+        SELECT o._id, o.sendersreference, o.created, o.processed, o.processedstatus, o.type
+        FROM notifications.orders o
+        WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname
+    ),
+    order_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            od.processedstatus::TEXT AS status,
+            GREATEST(od.created, COALESCE(od.processed, od.created)) AS last_update,
+            NULL::TEXT AS destination,
+            od.type::TEXT AS type
+        FROM order_data od
+    ),
+    email_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            e.result::TEXT AS status,
+            e.resulttime AS last_update,
+            e.toaddress AS destination,
+            od.type::TEXT AS type
+        FROM order_data od
+        JOIN notifications.emailnotifications e ON e._orderid = od._id
+    ),
+    sms_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            s.result::TEXT AS status,
+            s.resulttime AS last_update,
+            s.mobilenumber AS destination,
+            od.type::TEXT AS type
+        FROM order_data od
+        JOIN notifications.smsnotifications s ON s._orderid = od._id
+    )
+    SELECT * FROM order_tracking
+    UNION ALL
+    SELECT * FROM email_tracking
+    UNION ALL
+    SELECT * FROM sms_tracking;
+END;
+$$ LANGUAGE plpgsql;
+
+COMMENT ON FUNCTION notifications.get_shipment_tracking_v2(UUID, TEXT) IS
+'Returns delivery tracking information for a notification identified by the given alternate identifier and creator name.
+
+Includes:
+ - Order-level tracking (reference and status)
+ - Email notification tracking (status, result time, destination)
+ - SMS notification tracking (status, result time, destination)
+
+If no matching order exists, an empty result set is returned.';
diff --git a/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql b/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql
index 7323359f8..8e24c08c2 100644
--- a/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql
+++ b/src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql
@@ -38,3 +38,30 @@ BEGIN
    RETURN _orderid;
 END;
 $BODY$;
+
+-- Add new overload that includes the 'type' parameter
+CREATE OR REPLACE FUNCTION notifications.insertorder(
+	_alternateid uuid,
+	_creatorname text,
+	_sendersreference text,
+	_created timestamp with time zone,
+	_requestedsendtime timestamp with time zone,
+	_notificationorder jsonb,
+	_sendingtimepolicy integer,
+	_type text)
+    RETURNS bigint
+    LANGUAGE 'plpgsql'
+    COST 100
+    VOLATILE PARALLEL UNSAFE
+AS $BODY$
+
+DECLARE
+_orderid BIGINT;
+BEGIN
+	INSERT INTO notifications.orders(alternateid, creatorname, sendersreference, created, requestedsendtime, processed, notificationorder, sendingtimepolicy, type) 
+	VALUES (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _created, _notificationorder, _sendingtimepolicy, _type::public.notificationordertype)
+   RETURNING _id INTO _orderid;
+   
+   RETURN _orderid;
+END;
+$BODY$;
\ No newline at end of file
diff --git a/src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql b/src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql
new file mode 100644
index 000000000..e8917eb4b
--- /dev/null
+++ b/src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql
@@ -0,0 +1,895 @@
+-- This script is autogenerated from the tool DbTools. Do not edit manually.
+
+-- cancelorder.sql:
+CREATE OR REPLACE FUNCTION notifications.cancelorder(
+    _alternateid uuid,
+    _creatorname text
+)
+RETURNS TABLE(
+    cancelallowed boolean,
+    alternateid uuid,
+    creatorname text,
+    sendersreference text,
+    created timestamp with time zone,                  
+    requestedsendtime timestamp with time zone,
+    processed timestamp with time zone,
+    processedstatus orderprocessingstate,
+    notificationchannel text,
+    ignorereservation boolean,
+    resourceid text,
+    conditionendpoint text,
+    generatedemailcount bigint,
+    succeededemailcount bigint,
+    generatedsmscount bigint, 
+    succeededsmscount bigint
+) 
+LANGUAGE plpgsql
+AS $$
+DECLARE
+    order_record RECORD;
+BEGIN
+    -- Retrieve the order and its status
+    SELECT o.requestedsendtime, o.processedstatus
+    INTO order_record
+    FROM notifications.orders o
+    WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname;
+
+    -- If no order is found, return an empty result set
+    IF NOT FOUND THEN
+        RETURN;
+    END IF;
+    
+     -- Check if order is already cancelled
+     IF order_record.processedstatus = 'Cancelled' THEN
+        RETURN QUERY 
+        SELECT TRUE AS cancelallowed,
+           order_details.*
+        FROM notifications.getorder_includestatus_v4(_alternateid, _creatorname) AS order_details;
+     ELSIF (order_record.requestedsendtime <= NOW() + INTERVAL '5 minutes' or order_record.processedstatus != 'Registered') THEN
+        RETURN QUERY 
+        SELECT FALSE AS cancelallowed, NULL::uuid, NULL::text, NULL::text, NULL::timestamp with time zone, NULL::timestamp with time zone, NULL::timestamp with time zone, NULL::orderprocessingstate, NULL::text, NULL::boolean, NULL::text, NULL::text, NULL::bigint, NULL::bigint, NULL::bigint, NULL::bigint;
+     ELSE 
+        -- Cancel the order by updating its status
+        UPDATE notifications.orders o
+        SET processedstatus = 'Cancelled', processed = NOW()
+        WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname;
+
+        -- Retrieve the updated order details
+        RETURN QUERY 
+        SELECT TRUE AS cancelallowed,
+               order_details.*
+        FROM notifications.getorder_includestatus_v4(_alternateid, _creatorname) AS order_details;
+    END IF;      
+END;
+$$;
+
+
+-- getemailrecipients.sql:
+CREATE OR REPLACE FUNCTION notifications.getemailrecipients_v2(_alternateid uuid)
+RETURNS TABLE(
+    recipientorgno text, 
+    recipientnin text, 
+    toaddress text
+) 
+LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+__orderid BIGINT := (SELECT _id from notifications.orders
+			where alternateid = _alternateid);
+BEGIN
+RETURN query 
+	SELECT e.recipientorgno, e.recipientnin, e.toaddress
+	FROM notifications.emailnotifications e
+	WHERE e._orderid = __orderid;
+END;
+$BODY$;
+
+-- getemailsstatusnewupdatestatus.sql:
+CREATE OR REPLACE FUNCTION notifications.getemails_statusnew_updatestatus()
+    RETURNS TABLE(alternateid uuid, subject text, body text, fromaddress text, toaddress text, contenttype text) 
+    LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+    latest_email_timeout TIMESTAMP WITH TIME ZONE;
+BEGIN
+    SELECT emaillimittimeout 
+    INTO latest_email_timeout 
+    FROM notifications.resourcelimitlog 
+    WHERE id = (SELECT MAX(id) FROM notifications.resourcelimitlog);
+
+    -- Check if the latest email timeout is set and valid
+    IF latest_email_timeout IS NOT NULL THEN
+        IF latest_email_timeout >= NOW() THEN
+            RETURN QUERY 
+            SELECT NULL::uuid AS alternateid, 
+                   NULL::text AS subject, 
+                   NULL::text AS body, 
+                   NULL::text AS fromaddress, 
+                   NULL::text AS toaddress, 
+                   NULL::text AS contenttype 
+            WHERE FALSE;
+            RETURN;
+        ELSE 
+            UPDATE notifications.resourcelimitlog 
+            SET emaillimittimeout = NULL 
+            WHERE id = (SELECT MAX(id) FROM notifications.resourcelimitlog);
+        END IF;
+    END IF;
+    
+    RETURN QUERY 
+    WITH updated AS (
+        UPDATE notifications.emailnotifications
+        SET result = 'Sending', resulttime = now()
+        WHERE result = 'New' 
+        RETURNING notifications.emailnotifications.alternateid, 
+                  _orderid, 
+                  notifications.emailnotifications.toaddress, 
+                  notifications.emailnotifications.customizedsubject, 
+                  notifications.emailnotifications.customizedbody
+    )
+    SELECT u.alternateid, 
+           CASE WHEN u.customizedsubject IS NOT NULL AND u.customizedsubject <> '' THEN u.customizedsubject ELSE et.subject END AS subject, 
+           CASE WHEN u.customizedbody IS NOT NULL AND u.customizedbody <> '' THEN u.customizedbody ELSE et.body END AS body, 
+           et.fromaddress, 
+           u.toaddress, 
+           et.contenttype 
+    FROM updated u
+    JOIN notifications.emailtexts et ON u._orderid = et._orderid;    
+END;
+$BODY$;
+
+
+-- getemailsummary.sql:
+CREATE OR REPLACE FUNCTION notifications.getemailsummary_v2(
+	_alternateorderid uuid,
+	_creatorname text)
+    RETURNS TABLE(
+        sendersreference text, 
+        alternateid uuid, 
+        recipientorgno text, 
+        recipientnin text, 
+        toaddress text, 
+        result emailnotificationresulttype, 
+        resulttime timestamptz) 
+    LANGUAGE 'plpgsql'
+AS $BODY$
+
+	BEGIN
+		RETURN QUERY
+		   SELECT o.sendersreference, n.alternateid, n.recipientorgno, n.recipientnin, n.toaddress, n.result, n.resulttime
+			FROM notifications.emailnotifications n
+            LEFT JOIN notifications.orders o ON n._orderid = o._id
+			WHERE o.alternateid = _alternateorderid
+			and o.creatorname = _creatorname;
+        IF NOT FOUND THEN
+            RETURN QUERY
+            SELECT o.sendersreference, NULL::uuid, NULL::text, NULL::text, NULL::text, NULL::emailnotificationresulttype, NULL::timestamptz
+            FROM notifications.orders o
+            WHERE o.alternateid = _alternateorderid
+            and o.creatorname = _creatorname;
+        END IF;
+	END;
+$BODY$;
+
+-- getmetrics.sql:
+CREATE OR REPLACE FUNCTION notifications.getmetrics(
+    month_input int,
+    year_input int
+)
+RETURNS TABLE (
+    org text,
+    placed_orders bigint,
+    sent_emails bigint,
+    succeeded_emails bigint,
+    sent_sms bigint,
+    succeeded_sms bigint
+)
+AS $$
+BEGIN
+    RETURN QUERY
+    SELECT
+        o.creatorname,
+        COUNT(DISTINCT o._id) AS placed_orders,
+        SUM(CASE WHEN e._id IS NOT NULL THEN 1 ELSE 0 END) AS sent_emails,
+        SUM(CASE WHEN e.result IN ('Delivered', 'Succeeded') THEN 1 ELSE 0 END) AS succeeded_emails, 
+        SUM(CASE WHEN s._id IS NOT NULL THEN s.smscount ELSE 0 END) AS sent_sms,
+        SUM(CASE WHEN s.result = 'Accepted' THEN 1 ELSE 0 END) AS succeeded_sms
+    FROM notifications.orders o
+    LEFT JOIN notifications.emailnotifications e ON o._id = e._orderid
+    LEFT JOIN notifications.smsnotifications s ON o._id = s._orderid
+    WHERE EXTRACT(MONTH FROM o.requestedsendtime) = month_input
+        AND EXTRACT(YEAR FROM o.requestedsendtime) = year_input
+    GROUP BY o.creatorname;
+END;
+$$ LANGUAGE plpgsql;
+
+
+-- getorderincludestatus.sql:
+CREATE OR REPLACE FUNCTION notifications.getorder_includestatus_v4(
+    _alternateid uuid,
+    _creatorname text
+)
+RETURNS TABLE(
+    alternateid uuid,
+    creatorname text,
+    sendersreference text,
+    created timestamp with time zone,                  
+    requestedsendtime timestamp with time zone,
+    processed timestamp with time zone,
+    processedstatus orderprocessingstate,
+    notificationchannel text,
+    ignorereservation boolean,
+    resourceid text,
+    conditionendpoint text,
+    generatedemailcount bigint,
+    succeededemailcount bigint,
+    generatedsmscount bigint, 
+    succeededsmscount bigint
+) 
+LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+    _target_orderid INTEGER;
+    _succeededEmailCount BIGINT;
+    _generatedEmailCount BIGINT;
+    _succeededSmsCount BIGINT;
+    _generatedSmsCount BIGINT;
+BEGIN
+    SELECT _id INTO _target_orderid 
+    FROM notifications.orders
+    WHERE orders.alternateid = _alternateid 
+    AND orders.creatorname = _creatorname;
+    
+    SELECT
+        SUM(CASE WHEN result IN ('Delivered', 'Succeeded') THEN 1 ELSE 0 END), 
+        COUNT(1) AS generatedEmailCount
+    INTO _succeededEmailCount, _generatedEmailCount
+    FROM notifications.emailnotifications
+    WHERE emailnotifications._orderid = _target_orderid;
+    
+    SELECT      
+        SUM(CASE WHEN result = 'Accepted' THEN 1 ELSE 0 END), 
+        COUNT(1) AS generatedSmsCount
+    INTO _succeededSmsCount, _generatedSmsCount
+    FROM notifications.smsnotifications
+    WHERE smsnotifications._orderid = _target_orderid;
+
+    RETURN QUERY
+    SELECT 
+        orders.alternateid,
+        orders.creatorname,
+        orders.sendersreference,
+        orders.created,
+        orders.requestedsendtime,
+        orders.processed,
+        orders.processedstatus,
+        orders.notificationorder->>'NotificationChannel',
+        CASE 
+            WHEN orders.notificationorder->>'IgnoreReservation' IS NULL THEN NULL
+            ELSE (orders.notificationorder->>'IgnoreReservation')::BOOLEAN
+        END AS IgnoreReservation,
+        orders.notificationorder->>'ResourceId',
+        orders.notificationorder->>'ConditionEndpoint',
+        _generatedEmailCount,
+        _succeededEmailCount,
+        _generatedSmsCount, 
+        _succeededSmsCount
+    FROM
+        notifications.orders AS orders
+    WHERE 
+        orders._id = _target_orderid;
+END;
+$BODY$;
+
+
+-- getorderschaintracking.sql:
+-- Retrieves tracking information for a notification order chain using the creator's short name and idempotency identifier.
+CREATE OR REPLACE FUNCTION notifications.get_orders_chain_tracking
+(
+    _creatorname text,
+    _idempotencyid text
+)
+RETURNS TABLE (
+    orders_chain_id uuid,
+    shipment_id uuid,
+    senders_reference text,
+    reminders jsonb
+) 
+LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+    v_record_exists boolean;
+BEGIN
+    -- Check if record exists first to provide better error handling
+    SELECT EXISTS (
+        SELECT 1 
+        FROM notifications.orderschain 
+        WHERE creatorname = _creatorname
+        AND idempotencyid = _idempotencyid
+    ) INTO v_record_exists;
+    
+    IF NOT v_record_exists THEN
+        -- Return empty result set with no rows
+        RETURN;
+    END IF;
+
+    RETURN QUERY
+    SELECT 
+        orders_chain.orderid AS orders_chain_id,
+        (orders_chain.orderchain->>'OrderId')::uuid AS shipment_id,
+        orders_chain.orderchain->>'SendersReference' AS senders_reference,
+        -- Extract only OrderId and SendersReference from each reminder
+        COALESCE(
+            (SELECT jsonb_agg(
+                jsonb_build_object(
+                    'ShipmentId', reminder->>'OrderId',
+                    'SendersReference', reminder->>'SendersReference'
+                )
+            )
+            FROM jsonb_array_elements(
+                CASE 
+                    WHEN jsonb_typeof(orders_chain.orderchain->'Reminders') = 'array' AND 
+                         (orders_chain.orderchain->'Reminders') IS NOT NULL AND
+                         (orders_chain.orderchain->'Reminders') <> 'null'::jsonb
+                    THEN orders_chain.orderchain->'Reminders'
+                    ELSE '[]'::jsonb
+                END
+            ) AS reminder),
+            '[]'::jsonb
+        ) AS reminders
+    FROM 
+        notifications.orderschain orders_chain
+    WHERE 
+        orders_chain.creatorname = _creatorname
+        AND orders_chain.idempotencyid = _idempotencyid;
+END;
+$BODY$;
+
+COMMENT ON FUNCTION notifications.get_orders_chain_tracking IS 
+'Retrieves tracking information for a notification order chain using the creator''s short name and idempotency identifier.
+
+This function enables idempotent operations by allowing clients to retrieve previously submitted
+notification chain information without creating duplicates.
+
+Parameters:
+- _creatorname: The short name of the creator that originally submitted the notification order chain
+- _idempotencyid: The idempotency identifier that was defined when the order chain was created
+
+Returns a table with the following columns:
+- orders_chain_id: The unique identifier for the entire notification order chain
+- shipment_id: The unique identifier for the main notification order
+- senders_reference: The sender''s reference for the main notification order (may be null)
+- reminders: A JSON array containing tracking information for any reminder notifications
+
+The reminders JSON array contains objects with the following structure:
+- OrderId: The unique identifier for the reminder notification order
+- SendersReference: The sender''s reference for the reminder notification (may be null).';
+
+
+-- getorderspastsendtimeupdatestatus.sql:
+CREATE OR REPLACE FUNCTION notifications.getorders_pastsendtime_updatestatus()
+    RETURNS TABLE(notificationorders jsonb)
+    LANGUAGE 'plpgsql'
+AS $BODY$
+BEGIN
+RETURN QUERY
+	UPDATE notifications.orders
+	SET processedstatus = 'Processing'
+	WHERE _id IN (select _id
+				 from notifications.orders
+				 where processedstatus = 'Registered'
+				 and requestedsendtime <= now() + INTERVAL '1 minute'
+				 limit 50)
+	RETURNING notificationorder AS notificationorders;
+END;
+$BODY$;
+
+-- getshipmenttracking.sql:
+CREATE OR REPLACE FUNCTION notifications.get_shipment_tracking(
+    _alternateid UUID,
+    _creatorname TEXT)
+RETURNS TABLE (
+    reference     TEXT,
+    status        TEXT,
+    last_update   TIMESTAMPTZ,
+    destination   TEXT
+) AS $$
+DECLARE
+    v_order_exists BOOLEAN;
+BEGIN
+    -- Check for the existence of the order
+    SELECT EXISTS (
+        SELECT 1
+        FROM notifications.orders o
+        WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname
+    )
+    INTO v_order_exists;
+
+    -- Return empty set if no order is found
+    IF NOT v_order_exists THEN
+        RETURN;
+    END IF;
+
+    -- Return combined tracking info
+    RETURN QUERY
+    WITH order_data AS (
+        SELECT o._id, o.sendersreference, o.created, o.processed, o.processedstatus
+        FROM notifications.orders o
+        WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname
+    ),
+    order_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            od.processedstatus::TEXT AS status,
+            GREATEST(od.created, COALESCE(od.processed, od.created)) AS last_update,
+            NULL::TEXT AS destination
+        FROM order_data od
+    ),
+    email_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            e.result::TEXT AS status,
+            e.resulttime AS last_update,
+            e.toaddress AS destination
+        FROM order_data od
+        JOIN notifications.emailnotifications e ON e._orderid = od._id
+    ),
+    sms_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            s.result::TEXT AS status,
+            s.resulttime AS last_update,
+            s.mobilenumber AS destination
+        FROM order_data od
+        JOIN notifications.smsnotifications s ON s._orderid = od._id
+    )
+    SELECT * FROM order_tracking
+    UNION ALL
+    SELECT * FROM email_tracking
+    UNION ALL
+    SELECT * FROM sms_tracking;
+END;
+$$ LANGUAGE plpgsql;
+
+COMMENT ON FUNCTION notifications.get_shipment_tracking(UUID, TEXT) IS
+'Returns delivery tracking information for a notification identified by the given alternate identifier and creator name.
+
+Includes:
+ - Order-level tracking (reference and status)
+ - Email notification tracking (status, result time, destination)
+ - SMS notification tracking (status, result time, destination)
+
+If no matching order exists, an empty result set is returned.';
+
+
+-- This is a new version to return the type of the notification
+CREATE OR REPLACE FUNCTION notifications.get_shipment_tracking_v2(
+    _alternateid UUID,
+    _creatorname TEXT)
+RETURNS TABLE (
+    reference     TEXT,
+    status        TEXT,
+    last_update   TIMESTAMPTZ,
+    destination   TEXT,
+    type          TEXT
+) AS $$
+DECLARE
+    v_order_exists BOOLEAN;
+BEGIN
+    -- Check for the existence of the order
+    SELECT EXISTS (
+        SELECT 1
+        FROM notifications.orders o
+        WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname
+    )
+    INTO v_order_exists;
+
+    -- Return empty set if no order is found
+    IF NOT v_order_exists THEN
+        RETURN;
+    END IF;
+
+    -- Return combined tracking info
+    RETURN QUERY
+    WITH order_data AS (
+        SELECT o._id, o.sendersreference, o.created, o.processed, o.processedstatus, o.type
+        FROM notifications.orders o
+        WHERE o.alternateid = _alternateid AND o.creatorname = _creatorname
+    ),
+    order_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            od.processedstatus::TEXT AS status,
+            GREATEST(od.created, COALESCE(od.processed, od.created)) AS last_update,
+            NULL::TEXT AS destination,
+            od.type::TEXT AS type
+        FROM order_data od
+    ),
+    email_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            e.result::TEXT AS status,
+            e.resulttime AS last_update,
+            e.toaddress AS destination,
+            od.type::TEXT AS type
+        FROM order_data od
+        JOIN notifications.emailnotifications e ON e._orderid = od._id
+    ),
+    sms_tracking AS (
+        SELECT
+            od.sendersreference AS reference,
+            s.result::TEXT AS status,
+            s.resulttime AS last_update,
+            s.mobilenumber AS destination,
+            od.type::TEXT AS type
+        FROM order_data od
+        JOIN notifications.smsnotifications s ON s._orderid = od._id
+    )
+    SELECT * FROM order_tracking
+    UNION ALL
+    SELECT * FROM email_tracking
+    UNION ALL
+    SELECT * FROM sms_tracking;
+END;
+$$ LANGUAGE plpgsql;
+
+COMMENT ON FUNCTION notifications.get_shipment_tracking_v2(UUID, TEXT) IS
+'Returns delivery tracking information for a notification identified by the given alternate identifier and creator name.
+
+Includes:
+ - Order-level tracking (reference and status)
+ - Email notification tracking (status, result time, destination)
+ - SMS notification tracking (status, result time, destination)
+
+If no matching order exists, an empty result set is returned.';
+
+
+-- getsmsrecipients.sql:
+CREATE OR REPLACE FUNCTION notifications.getsmsrecipients_v2(_orderid uuid)
+RETURNS TABLE(
+  recipientorgno text, 
+  recipientnin text,
+  mobilenumber text
+) 
+LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+__orderid BIGINT := (SELECT _id from notifications.orders
+			where alternateid = _orderid);
+BEGIN
+RETURN query 
+	SELECT s.recipientorgno, s.recipientnin, s.mobilenumber
+	FROM notifications.smsnotifications s
+	WHERE s._orderid = __orderid;
+END;
+$BODY$;
+
+-- getsmsstatusnewupdatestatus.sql:
+-- This function is kept for backward compatibility and may be removed in future versions.
+-- Use notifications.getsms_statusnew_updatestatus(integer) instead.
+CREATE OR REPLACE FUNCTION notifications.getsms_statusnew_updatestatus()
+    RETURNS TABLE(alternateid uuid, sendernumber text, mobilenumber text, body text) 
+    LANGUAGE 'plpgsql'
+AS $BODY$
+BEGIN
+    RETURN QUERY 
+    WITH updated AS (
+        UPDATE notifications.smsnotifications
+        SET result = 'Sending', resulttime = now()
+        WHERE result = 'New' 
+        RETURNING notifications.smsnotifications.alternateid, 
+                  _orderid, 
+                  notifications.smsnotifications.mobilenumber,
+                  notifications.smsnotifications.customizedbody
+    )
+    SELECT u.alternateid, 
+           st.sendernumber, 
+           u.mobilenumber, 
+           CASE WHEN u.customizedbody IS NOT NULL AND u.customizedbody <> '' THEN u.customizedbody ELSE st.body END AS body
+    FROM updated u
+    JOIN notifications.smstexts st ON u._orderid = st._orderid;        
+END;
+$BODY$;
+
+-- FUNCTION: notifications.getsms_statusnew_updatestatus(integer)
+CREATE OR REPLACE FUNCTION NOTIFICATIONS.GETSMS_STATUSNEW_UPDATESTATUS (_SENDINGTIMEPOLICY INTEGER) 
+RETURNS TABLE (
+    ALTERNATEID UUID,
+    SENDERNUMBER TEXT,
+    MOBILENUMBER TEXT,
+    BODY TEXT
+) 
+LANGUAGE 'plpgsql' 
+COST 100 
+VOLATILE 
+PARALLEL UNSAFE 
+ROWS 1000 
+AS $BODY$
+BEGIN
+    RETURN QUERY 
+    WITH updated AS (
+        UPDATE notifications.smsnotifications s
+        SET result = 'Sending', resulttime = now()
+        FROM notifications.orders o
+        WHERE s.result = 'New' 
+          AND s._orderid = o._id
+          AND (
+              (_sendingtimepolicy = 1 AND o.sendingtimepolicy = 1)
+           OR (_sendingtimepolicy = 2 AND (o.sendingtimepolicy = 2 OR o.sendingtimepolicy IS NULL))
+          )
+        RETURNING s.alternateid, 
+                  s._orderid, 
+                  s.mobilenumber,
+                  s.customizedbody
+    )
+    SELECT u.alternateid, 
+           st.sendernumber, 
+           u.mobilenumber, 
+           CASE 
+               WHEN u.customizedbody IS NOT NULL AND u.customizedbody <> '' 
+               THEN u.customizedbody 
+               ELSE st.body 
+           END AS body
+    FROM updated u
+    JOIN notifications.smstexts st ON u._orderid = st._orderid;
+END;
+$BODY$;
+
+COMMENT ON FUNCTION NOTIFICATIONS.GETSMS_STATUSNEW_UPDATESTATUS (INTEGER) IS 'Reads all entries in smsnotifications where result status is New.
+ Result is then updated to Sending. Parameter _sendingtimepolicy is used to
+ filter the returned entries based on the policy for scheduling set on the related
+ order row. If this is null, it is treated as Daytime, which is the default setting';
+
+
+-- getsmssummary.sql:
+CREATE OR REPLACE FUNCTION notifications.getsmssummary_v2(
+	_alternateorderid uuid,
+	_creatorname text)
+    RETURNS TABLE(
+        sendersreference text, 
+        alternateid uuid, 
+        recipientorgno text, 
+        recipientnin text, 
+        mobilenumber text, 
+        result smsnotificationresulttype, 
+        resulttime timestamptz) 
+    LANGUAGE 'plpgsql'
+AS $BODY$
+
+	BEGIN
+		RETURN QUERY
+		   SELECT o.sendersreference, n.alternateid, n.recipientorgno, n.recipientnin, n.mobilenumber, n.result, n.resulttime
+			FROM notifications.smsnotifications n
+            LEFT JOIN notifications.orders o ON n._orderid = o._id
+			WHERE o.alternateid = _alternateorderid
+			and o.creatorname = _creatorname;
+        IF NOT FOUND THEN
+            RETURN QUERY
+            SELECT o.sendersreference, NULL::uuid, NULL::text, NULL::text, NULL::text, NULL::smsnotificationresulttype, NULL::timestamptz
+            FROM notifications.orders o
+            WHERE o.alternateid = _alternateorderid
+            and o.creatorname = _creatorname;
+        END IF;
+	END;
+$BODY$;
+
+-- insertemailnotification.sql:
+CREATE OR REPLACE PROCEDURE notifications.insertemailnotification(
+    _orderid uuid,
+    _alternateid uuid,
+    _recipientorgno TEXT,
+    _recipientnin TEXT,
+    _toaddress TEXT,
+    _customizedbody TEXT,
+    _customizedsubject TEXT,
+    _result TEXT,
+    _resulttime timestamptz,
+    _expirytime timestamptz
+)
+LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+    __orderid BIGINT;
+BEGIN
+    SELECT _id INTO __orderid 
+    FROM notifications.orders
+    WHERE alternateid = _orderid;
+
+    INSERT INTO notifications.emailnotifications(
+        _orderid,
+        alternateid,
+        recipientorgno,
+        recipientnin,
+        toaddress,
+        customizedbody,
+        customizedsubject,
+        result,
+        resulttime,
+        expirytime
+    )
+    VALUES (
+        __orderid,
+        _alternateid,
+        _recipientorgno,
+        _recipientnin,
+        _toaddress,
+        _customizedbody,
+        _customizedsubject,
+        _result::emailnotificationresulttype,
+        _resulttime,
+        _expirytime
+    );
+END;
+$BODY$;
+
+-- insertemailtext.sql:
+CREATE OR REPLACE PROCEDURE notifications.insertemailtext(__orderid BIGINT, _fromaddress TEXT, _subject TEXT, _body TEXT, _contenttype TEXT)
+LANGUAGE 'plpgsql'
+AS $BODY$
+BEGIN
+INSERT INTO notifications.emailtexts(_orderid, fromaddress, subject, body, contenttype)
+	VALUES (__orderid, _fromaddress, _subject, _body, _contenttype);
+END;
+$BODY$;
+
+
+-- insertorder.sql:
+CREATE OR REPLACE FUNCTION notifications.insertorder(_alternateid UUID, _creatorname TEXT, _sendersreference TEXT, _created TIMESTAMPTZ, _requestedsendtime TIMESTAMPTZ, _notificationorder JSONB)
+RETURNS BIGINT
+    LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+_orderid BIGINT;
+BEGIN
+	INSERT INTO notifications.orders(alternateid, creatorname, sendersreference, created, requestedsendtime, processed, notificationorder) 
+	VALUES (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _created, _notificationorder)
+   RETURNING _id INTO _orderid;
+   
+   RETURN _orderid;
+END;
+$BODY$;
+
+-- Postgres supports function overloading - so this function has the same name, but one additional parameter: sendingTimePolicy
+CREATE OR REPLACE FUNCTION notifications.insertorder(
+	_alternateid uuid,
+	_creatorname text,
+	_sendersreference text,
+	_created timestamp with time zone,
+	_requestedsendtime timestamp with time zone,
+	_notificationorder jsonb,
+	_sendingtimepolicy integer)
+    RETURNS bigint
+    LANGUAGE 'plpgsql'
+    COST 100
+    VOLATILE PARALLEL UNSAFE
+AS $BODY$
+
+DECLARE
+_orderid BIGINT;
+BEGIN
+	INSERT INTO notifications.orders(alternateid, creatorname, sendersreference, created, requestedsendtime, processed, notificationorder, sendingtimepolicy) 
+	VALUES (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _created, _notificationorder, _sendingtimepolicy)
+   RETURNING _id INTO _orderid;
+   
+   RETURN _orderid;
+END;
+$BODY$;
+
+-- Add new overload that includes the 'type' parameter
+CREATE OR REPLACE FUNCTION notifications.insertorder(
+	_alternateid uuid,
+	_creatorname text,
+	_sendersreference text,
+	_created timestamp with time zone,
+	_requestedsendtime timestamp with time zone,
+	_notificationorder jsonb,
+	_sendingtimepolicy integer,
+	_type text)
+    RETURNS bigint
+    LANGUAGE 'plpgsql'
+    COST 100
+    VOLATILE PARALLEL UNSAFE
+AS $BODY$
+
+DECLARE
+_orderid BIGINT;
+BEGIN
+	INSERT INTO notifications.orders(alternateid, creatorname, sendersreference, created, requestedsendtime, processed, notificationorder, sendingtimepolicy, type) 
+	VALUES (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _created, _notificationorder, _sendingtimepolicy, _type::public.notificationordertype)
+   RETURNING _id INTO _orderid;
+   
+   RETURN _orderid;
+END;
+$BODY$;
+
+-- insertorderchain.sql:
+CREATE OR REPLACE PROCEDURE notifications.insertorderchain(
+    _orderid UUID,
+    _idempotencyid TEXT,
+    _creatorname TEXT,
+    _created TIMESTAMP with time zone,
+    _orderchain JSONB
+)
+LANGUAGE 'plpgsql'
+AS $BODY$
+BEGIN
+    INSERT INTO notifications.orderschain(
+        orderid,
+        idempotencyid,
+        creatorname,
+        created,
+        processed,
+        orderchain
+    )
+    VALUES (
+        _orderid,
+        _idempotencyid,
+        _creatorname,
+        _created,
+        _created,
+        _orderchain
+    );
+END;
+$BODY$;
+
+
+-- insertsmsnotification.sql:
+CREATE OR REPLACE PROCEDURE notifications.insertsmsnotification(
+    _orderid uuid,
+    _alternateid uuid,
+    _recipientorgno TEXT,
+    _recipientnin TEXT,
+    _mobilenumber TEXT,
+    _customizedbody TEXT,
+    _result TEXT,
+    _smscount integer,
+    _resulttime timestamptz,
+    _expirytime timestamptz
+)
+LANGUAGE 'plpgsql'
+AS $BODY$
+DECLARE
+    __orderid BIGINT;
+BEGIN
+    SELECT _id INTO __orderid 
+    FROM notifications.orders
+    WHERE alternateid = _orderid;
+
+    INSERT INTO notifications.smsnotifications(
+        _orderid,
+        alternateid,
+        recipientorgno,
+        recipientnin,
+        mobilenumber,
+        customizedbody,
+        result,
+        smscount,
+        resulttime,
+        expirytime
+    )
+    VALUES (
+        __orderid,
+        _alternateid,
+        _recipientorgno,
+        _recipientnin,
+        _mobilenumber,
+        _customizedbody,
+        _result::smsnotificationresulttype,
+        _smscount,
+        _resulttime,
+        _expirytime
+    );
+END;
+$BODY$;
+
+-- updateemailstatus.sql:
+CREATE OR REPLACE PROCEDURE notifications.updateemailstatus(_alternateid UUID, _result text, _operationid text)
+LANGUAGE 'plpgsql'
+AS $BODY$
+BEGIN
+	UPDATE notifications.emailnotifications 
+	SET result = _result::emailnotificationresulttype, resulttime = now(), operationid = _operationid
+	WHERE alternateid = _alternateid;
+END;
+$BODY$;
+
diff --git a/src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql b/src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql
new file mode 100644
index 000000000..2be0b9fed
--- /dev/null
+++ b/src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql
@@ -0,0 +1,9 @@
+DO $$
+BEGIN
+    IF NOT EXISTS (SELECT 1 
+                   FROM pg_type
+                   WHERE typname = 'notificationordertype'
+                   AND typnamespace = 'public'::regnamespace) THEN
+        CREATE TYPE public.notificationordertype AS ENUM ('Notification', 'Reminder');
+    END IF;
+END $$;
\ No newline at end of file
diff --git a/src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql b/src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql
new file mode 100644
index 000000000..e8ee10385
--- /dev/null
+++ b/src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql
@@ -0,0 +1,12 @@
+DO $$
+BEGIN
+    IF NOT EXISTS (SELECT 1
+                   FROM information_schema.columns 
+                   WHERE column_name = 'type'
+                   AND table_name   = 'orders'
+                   AND table_schema = 'notifications' ) THEN
+        
+        ALTER TABLE notifications.orders ADD COLUMN type public.notificationordertype 
+            NOT NULL DEFAULT 'Notification'::public.notificationordertype;
+    END IF;
+END $$;
\ No newline at end of file
diff --git a/src/Altinn.Notifications.Persistence/Repository/NotificationDeliveryManifestRepository.cs b/src/Altinn.Notifications.Persistence/Repository/NotificationDeliveryManifestRepository.cs
index 0371dba99..454d03566 100644
--- a/src/Altinn.Notifications.Persistence/Repository/NotificationDeliveryManifestRepository.cs
+++ b/src/Altinn.Notifications.Persistence/Repository/NotificationDeliveryManifestRepository.cs
@@ -19,12 +19,13 @@ public partial class NotificationDeliveryManifestRepository : INotificationDeliv
 {
     private readonly NpgsqlDataSource _dataSource;
 
+    private const string _typeColumnName = "type";
     private const string _statusColumnName = "status";
     private const string _referenceColumnName = "reference";
     private const string _lastUpdateColumnName = "last_update";
     private const string _destinationColumnName = "destination";
 
-    private const string _sqlGetShipmentTrackingInfo = "SELECT * FROM notifications.get_shipment_tracking($1, $2)"; // (_alternateid, _creatorname)
+    private const string _getShipmentTrackingInfoFunction = "SELECT * FROM notifications.get_shipment_tracking_v2($1, $2)"; // (_alternateid, _creatorname)
 
     /// <summary>
     /// Maps database SMS notification result types to ProcessingLifecycle values.
@@ -90,7 +91,7 @@ public NotificationDeliveryManifestRepository(NpgsqlDataSource dataSource)
     /// <inheritdoc />
     public async Task<INotificationDeliveryManifest?> GetDeliveryManifestAsync(Guid alternateId, string creatorName, CancellationToken cancellationToken)
     {
-        await using var command = _dataSource.CreateCommand(_sqlGetShipmentTrackingInfo);
+        await using var command = _dataSource.CreateCommand(_getShipmentTrackingInfoFunction);
         command.Parameters.AddWithValue(NpgsqlDbType.Uuid, alternateId);
         command.Parameters.AddWithValue(NpgsqlDbType.Text, creatorName);
 
@@ -105,6 +106,17 @@ public NotificationDeliveryManifestRepository(NpgsqlDataSource dataSource)
         return await CreateNotificationDeliveryManifestAsync(reader, alternateId, cancellationToken);
     }
 
+    /// <summary>
+    /// Retrieves the order type from the current database record.
+    /// </summary>
+    /// <param name="reader">Database reader positioned at a notification order data row.</param>
+    /// <returns>A string representing the order type (e.g., "Notification", "Reminder").</returns>
+    private static string GetType(NpgsqlDataReader reader)
+    {
+        var typeOrdinal = reader.GetOrdinal(_typeColumnName);
+        return reader.GetString(typeOrdinal);
+    }
+
     /// <summary>
     /// Converts a database SMS notification status to its corresponding <see cref="ProcessingLifecycle"/> enum value.
     /// </summary>
@@ -289,6 +301,8 @@ private static async Task<INotificationDeliveryManifest> CreateNotificationDeliv
     {
         var deliverableEntities = new List<IDeliveryManifest>();
 
+        var type = GetType(reader);
+
         var reference = await GetSenderReferenceAsync(reader, cancellationToken);
 
         var (status, lastUpdate) = await GetStatusAsync(reader, cancellationToken);
@@ -300,7 +314,7 @@ private static async Task<INotificationDeliveryManifest> CreateNotificationDeliv
 
         return new NotificationDeliveryManifest
         {
-            Type = "Notification",
+            Type = type,
             LastUpdate = lastUpdate,
             ShipmentId = alternateId,
             SendersReference = reference,
diff --git a/src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs b/src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs
index b4a11adef..c9fcbcc77 100644
--- a/src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs
+++ b/src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs
@@ -25,7 +25,7 @@ public class OrderRepository : IOrderRepository
 
     private const string _getOrderByIdSql = "select notificationorder from notifications.orders where alternateid=$1 and creatorname=$2";
     private const string _getOrdersBySendersReferenceSql = "select notificationorder from notifications.orders where sendersreference=$1 and creatorname=$2";
-    private const string _insertOrderSql = "select notifications.insertorder($1, $2, $3, $4, $5, $6, $7)"; // (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _notificationorder, _sendingtimepolicy)
+    private const string _insertOrderSql = "select notifications.insertorder($1, $2, $3, $4, $5, $6, $7, $8)"; // (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _notificationorder, _sendingtimepolicy, _type)
     private const string _insertEmailTextSql = "call notifications.insertemailtext($1, $2, $3, $4, $5)"; // (__orderid, _fromaddress, _subject, _body, _contenttype)
     private const string _insertSmsTextSql = "insert into notifications.smstexts(_orderid, sendernumber, body) VALUES ($1, $2, $3)"; // __orderid, _sendernumber, _body
     private const string _setProcessCompleted = "update notifications.orders set processedstatus =$1::orderprocessingstate where alternateid=$2";
@@ -307,9 +307,8 @@ public async Task<Result<NotificationOrderWithStatus, CancellationError>> Cancel
              reader.GetValue<bool?>("ignorereservation"),
              reader.GetValue<string?>("resourceid"),
              conditionEndpoint,
-             new ProcessingStatus(
-                 reader.GetValue<OrderProcessingStatus>("processedstatus"),
-                 reader.GetValue<DateTime>("processed")));
+             new ProcessingStatus(reader.GetValue<OrderProcessingStatus>("processedstatus"), reader.GetValue<DateTime>("processed")),
+             OrderType.Notification);
 
         int generatedEmail = (int)reader.GetValue<long>("generatedEmailCount");
         int succeededEmail = (int)reader.GetValue<long>("succeededEmailCount");
@@ -391,7 +390,7 @@ private static async Task<List<NotificationOrderChainShipment>> ExtractReminderS
 
     private static async Task<long> InsertOrder(NotificationOrder order, NpgsqlConnection connection, NpgsqlTransaction transaction, CancellationToken cancellationToken = default)
     {
-        await using NpgsqlCommand pgcom = new NpgsqlCommand(_insertOrderSql, connection, transaction);
+        await using NpgsqlCommand pgcom = new(_insertOrderSql, connection, transaction);
 
         pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, order.Id);
         pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, order.Creator.ShortName);
@@ -400,6 +399,7 @@ private static async Task<long> InsertOrder(NotificationOrder order, NpgsqlConne
         pgcom.Parameters.AddWithValue(NpgsqlDbType.TimestampTz, order.RequestedSendTime);
         pgcom.Parameters.AddWithValue(NpgsqlDbType.Jsonb, order);
         pgcom.Parameters.AddWithValue(NpgsqlDbType.Integer, (int?)order.SendingTimePolicy ?? (object)DBNull.Value);
+        pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, order.Type.ToString());
 
         await using NpgsqlDataReader reader = await pgcom.ExecuteReaderAsync(cancellationToken);
         await reader.ReadAsync(cancellationToken);
diff --git a/src/Altinn.Notifications/Controllers/FutureOrdersController.cs b/src/Altinn.Notifications/Controllers/FutureOrdersController.cs
index 53e5797e8..7f6e5013f 100644
--- a/src/Altinn.Notifications/Controllers/FutureOrdersController.cs
+++ b/src/Altinn.Notifications/Controllers/FutureOrdersController.cs
@@ -99,6 +99,16 @@ public async Task<ActionResult<NotificationOrderChainResponseExt>> Post(Notifica
                     return StatusCode(error.ErrorCode, problemDetails);
                 });
         }
+        catch (InvalidOperationException ex)
+        {
+            var problemDetails = new ProblemDetails
+            {
+                Status = 400,
+                Detail = ex.Message,
+                Title = "Invalid notification order request"
+            };
+            return StatusCode(400, problemDetails);
+        }
         catch (OperationCanceledException)
         {
             var problemDetails = new ProblemDetails
diff --git a/src/Altinn.Notifications/Controllers/ShipmentController.cs b/src/Altinn.Notifications/Controllers/ShipmentController.cs
index 1afd2356e..836226756 100644
--- a/src/Altinn.Notifications/Controllers/ShipmentController.cs
+++ b/src/Altinn.Notifications/Controllers/ShipmentController.cs
@@ -67,12 +67,26 @@ public async Task<ActionResult<NotificationDeliveryManifestExt>> GetById([FromRo
                 },
                 error =>
                 {
-                    return StatusCode(error.ErrorCode, error.ErrorMessage);
+                    var problemDetails = new ProblemDetails
+                    {
+                        Title = "Failed to retrieve shipment information",
+                        Detail = error.ErrorMessage,
+                        Status = error.ErrorCode
+                    };
+
+                    return StatusCode(error.ErrorCode, problemDetails);
                 });
         }
         catch (OperationCanceledException)
         {
-            return StatusCode(499, "Request terminated - The client disconnected or cancelled the request before the server could complete processing");
+            var problemDetails = new ProblemDetails
+            {
+                Title = "Request terminated",
+                Detail = "The client disconnected or cancelled the request before the server could complete processing.",
+                Status = 499
+            };
+
+            return StatusCode(499, problemDetails);
         }
     }
 }
diff --git a/src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs b/src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs
index f20e96fd2..71321824b 100644
--- a/src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs
+++ b/src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs
@@ -52,6 +52,7 @@ public static NotificationOrderChainRequest MapToNotificationOrderChainRequest(t
             .SetReminders(reminders)
             .SetOrderId(Guid.NewGuid())
             .SetOrderChainId(Guid.NewGuid())
+            .SetType(OrderType.Notification)
             .SetCreator(new Creator(creatorName))
             .SetDialogportenAssociation(dialogportenAssociation)
             .SetIdempotencyId(notificationOrderChainRequestExt.IdempotencyId)
@@ -107,6 +108,7 @@ private static NotificationReminder MapToNotificationReminder(this NotificationR
             },
 
             OrderId = Guid.NewGuid(),
+            Type = OrderType.Reminder,
             RequestedSendTime = requestedSendTime,
             DelayDays = notificationReminderExt.DelayDays,
             SendersReference = notificationReminderExt.SendersReference,
diff --git a/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/NotificationDeliveryManifestRepositoryTests.cs b/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/NotificationDeliveryManifestRepositoryTests.cs
index 3116b31d5..33b60431d 100644
--- a/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/NotificationDeliveryManifestRepositoryTests.cs
+++ b/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/NotificationDeliveryManifestRepositoryTests.cs
@@ -83,6 +83,7 @@ public async Task GetDeliveryManifestAsync_WhenCreatorNameDoesntMatch_ReturnsNul
             Id = orderId,
             Creator = new(creator),
             Created = creationDateTime,
+            Type = OrderType.Notification,
             SendersReference = senderReference,
             RequestedSendTime = requestedSendTime,
             SendingTimePolicy = SendingTimePolicy.Daytime,
@@ -147,6 +148,7 @@ public async Task GetDeliveryManifestAsync_WithVariousOrderStatuses_MapsStatuses
             Id = orderId,
             Creator = new(creator),
             Created = DateTime.UtcNow,
+            Type = OrderType.Notification,
             SendersReference = senderReference,
             SendingTimePolicy = SendingTimePolicy.Anytime,
             RequestedSendTime = DateTime.UtcNow.AddMinutes(30),
@@ -219,6 +221,7 @@ public async Task GetDeliveryManifestAsync_WithVariousOrderStatuses_MapsStatuses
 
         // Verify order status
         Assert.Equal(senderReference, deliveryManifest.SendersReference);
+        Assert.Equal(OrderType.Notification.ToString(), deliveryManifest.Type);
         Assert.Equal(ProcessingLifecycle.Order_Completed, deliveryManifest.Status);
 
         // Verify recipients collection
@@ -265,6 +268,7 @@ public async Task GetDeliveryManifestAsync_WhenNoNotificationsExist_ReturnsCorre
             Id = orderId,
             Creator = new(creator),
             Created = creationDateTime,
+            Type = OrderType.Notification,
             SendersReference = senderReference,
             RequestedSendTime = requestedSendTime,
             SendingTimePolicy = SendingTimePolicy.Daytime,
@@ -295,9 +299,9 @@ public async Task GetDeliveryManifestAsync_WhenNoNotificationsExist_ReturnsCorre
         Assert.NotNull(deliveryManifest.Type);
         Assert.NotEmpty(deliveryManifest.Type);
         Assert.Equal(orderId, deliveryManifest.ShipmentId);
-        Assert.Equal("Notification", deliveryManifest.Type);
         Assert.True(deliveryManifest.LastUpdate > DateTime.MinValue);
         Assert.Equal(senderReference, deliveryManifest.SendersReference);
+        Assert.Equal(OrderType.Notification.ToString(), deliveryManifest.Type);
         Assert.Equal(ProcessingLifecycle.Order_Registered, deliveryManifest.Status);
 
         Assert.NotNull(deliveryManifest.Recipients);
@@ -334,6 +338,7 @@ public async Task GetDeliveryManifestAsync_WhenSingleSmsNotificationExists_Retur
             Id = orderId,
             Creator = new(creator),
             Created = creationDateTime,
+            Type = OrderType.Notification,
             SendersReference = senderReference,
             RequestedSendTime = requestedSendTime,
             SendingTimePolicy = SendingTimePolicy.Daytime,
@@ -382,9 +387,9 @@ public async Task GetDeliveryManifestAsync_WhenSingleSmsNotificationExists_Retur
         Assert.NotNull(deliveryManifest.Type);
         Assert.NotEmpty(deliveryManifest.Type);
         Assert.Equal(orderId, deliveryManifest.ShipmentId);
-        Assert.Equal("Notification", deliveryManifest.Type);
         Assert.True(deliveryManifest.LastUpdate > DateTime.MinValue);
         Assert.Equal(senderReference, deliveryManifest.SendersReference);
+        Assert.Equal(OrderType.Notification.ToString(), deliveryManifest.Type);
         Assert.Equal(ProcessingLifecycle.Order_Registered, deliveryManifest.Status);
 
         Assert.NotNull(deliveryManifest.Recipients);
@@ -427,6 +432,7 @@ public async Task GetDeliveryManifestAsync_WhenSingleEmailNotificationExists_Ret
             Id = orderId,
             Creator = new(creator),
             Created = creationDateTime,
+            Type = OrderType.Reminder,
             SendersReference = senderReference,
             RequestedSendTime = requestedSendTime,
             SendingTimePolicy = SendingTimePolicy.Anytime,
@@ -474,9 +480,9 @@ public async Task GetDeliveryManifestAsync_WhenSingleEmailNotificationExists_Ret
         Assert.NotNull(deliveryManifest.Type);
         Assert.NotEmpty(deliveryManifest.Type);
         Assert.Equal(orderId, deliveryManifest.ShipmentId);
-        Assert.Equal("Notification", deliveryManifest.Type);
         Assert.True(deliveryManifest.LastUpdate > DateTime.MinValue);
         Assert.Equal(senderReference, deliveryManifest.SendersReference);
+        Assert.Equal(OrderType.Reminder.ToString(), deliveryManifest.Type);
         Assert.Equal(ProcessingLifecycle.Order_Registered, deliveryManifest.Status);
 
         Assert.NotNull(deliveryManifest.Recipients);
@@ -514,9 +520,9 @@ public async Task GetDeliveryManifestAsync_WithAlternatePhoneNumberFormats_Corre
             Creator = new(creator),
             Created = DateTime.UtcNow,
             SendersReference = senderReference,
-            RequestedSendTime = DateTime.UtcNow.AddMinutes(30),
             SendingTimePolicy = SendingTimePolicy.Anytime,
             NotificationChannel = NotificationChannel.Sms,
+            RequestedSendTime = DateTime.UtcNow.AddMinutes(30),
             Templates =
             [
                 new SmsTemplate("Test Sender", "Test SMS message content")
@@ -597,6 +603,7 @@ public async Task GetDeliveryManifestAsync_WhenBothEmailAndSmsNotificationsExist
             Id = orderId,
             Creator = new(creator),
             Created = creationDateTime,
+            Type = OrderType.Reminder,
             SendersReference = senderReference,
             RequestedSendTime = requestedSendTime,
             SendingTimePolicy = SendingTimePolicy.Daytime,
@@ -664,9 +671,9 @@ public async Task GetDeliveryManifestAsync_WhenBothEmailAndSmsNotificationsExist
         Assert.NotNull(deliveryManifest.Type);
         Assert.NotEmpty(deliveryManifest.Type);
         Assert.Equal(orderId, deliveryManifest.ShipmentId);
-        Assert.Equal("Notification", deliveryManifest.Type);
         Assert.True(deliveryManifest.LastUpdate > DateTime.MinValue);
         Assert.Equal(senderReference, deliveryManifest.SendersReference);
+        Assert.Equal(OrderType.Reminder.ToString(), deliveryManifest.Type);
         Assert.Equal(ProcessingLifecycle.Order_Registered, deliveryManifest.Status);
 
         Assert.NotNull(deliveryManifest.Recipients);
diff --git a/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/OrderRepositoryTests.cs b/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/OrderRepositoryTests.cs
index 7416b037c..6dbd111d0 100644
--- a/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/OrderRepositoryTests.cs
+++ b/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/OrderRepositoryTests.cs
@@ -274,6 +274,7 @@ public async Task Create_NotificationOrderChain_WithEmailRecipient_NoReminders_V
                 .SetOrderId(orderId)
                 .SetOrderChainId(orderChainId)
                 .SetCreator(new Creator("skd"))
+                .SetType(OrderType.Notification)
                 .SetRequestedSendTime(requestedSendTime)
                 .SetConditionEndpoint(new Uri("https://vg.no/condition"))
                 .SetIdempotencyId("EBEF8B94-3F8C-444E-BF94-6F6B1FA0417C")
@@ -300,6 +301,7 @@ public async Task Create_NotificationOrderChain_WithEmailRecipient_NoReminders_V
                 Id = orderId,
                 Creator = new("skd"),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestedSendTime,
                 NotificationChannel = NotificationChannel.Email,
                 ConditionEndpoint = new Uri("https://vg.no/condition"),
@@ -327,7 +329,7 @@ public async Task Create_NotificationOrderChain_WithEmailRecipient_NoReminders_V
             int orderChainCount = await PostgreUtil.RunSqlReturnOutput<int>(orderChainSql);
             Assert.Equal(1, orderChainCount);
 
-            string orderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{orderId}'";
+            string orderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{orderId}' and type ='Notification'";
             int ordersCount = await PostgreUtil.RunSqlReturnOutput<int>(orderSql);
             Assert.Equal(1, ordersCount);
 
@@ -357,6 +359,7 @@ public async Task Create_NotificationOrderChain_WithSmsRecipient_WithReminders_V
                 .SetOrderId(mainOrderId)
                 .SetOrderChainId(orderChainId)
                 .SetCreator(new Creator("ttd"))
+                .SetType(OrderType.Notification)
                 .SetSendersReference("ref-D3C9BA54")
                 .SetRequestedSendTime(requestedSendTime)
                 .SetIdempotencyId("F1E2D3C4-B5A6-9876-5432-1098ABCDEF01")
@@ -378,6 +381,7 @@ public async Task Create_NotificationOrderChain_WithSmsRecipient_WithReminders_V
                     new NotificationReminder
                     {
                         DelayDays = 3,
+                        Type = OrderType.Reminder,
                         OrderId = firstReminderOrderId,
                         SendersReference = "ref-reminder-A3BCFE4284D6",
                         RequestedSendTime = requestedSendTime.AddDays(3),
@@ -399,6 +403,7 @@ public async Task Create_NotificationOrderChain_WithSmsRecipient_WithReminders_V
                     new NotificationReminder
                     {
                         DelayDays = 7,
+                        Type = OrderType.Reminder,
                         OrderId = secondReminderOrderId,
                         SendersReference = "ref-reminder-F2491E785C2D",
                         RequestedSendTime = requestedSendTime.AddDays(7),
@@ -425,6 +430,7 @@ public async Task Create_NotificationOrderChain_WithSmsRecipient_WithReminders_V
                 Id = mainOrderId,
                 Creator = new("ttd"),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 SendersReference = "ref-D3C9BA54",
                 RequestedSendTime = requestedSendTime,
                 NotificationChannel = NotificationChannel.Sms,
@@ -445,6 +451,7 @@ public async Task Create_NotificationOrderChain_WithSmsRecipient_WithReminders_V
                     Creator = new("ttd"),
                     Id = firstReminderOrderId,
                     Created = creationDateTime,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestedSendTime.AddDays(3),
                     SendersReference = "ref-reminder-A3BCFE4284D6",
                     NotificationChannel = NotificationChannel.Sms,
@@ -463,6 +470,7 @@ public async Task Create_NotificationOrderChain_WithSmsRecipient_WithReminders_V
                     Creator = new("ttd"),
                     Id = secondReminderOrderId,
                     Created = creationDateTime,
+                    Type = OrderType.Reminder,
                     NotificationChannel = NotificationChannel.Sms,
                     SendersReference = "ref-reminder-F2491E785C2D",
                     RequestedSendTime = requestedSendTime.AddDays(7),
@@ -491,10 +499,10 @@ public async Task Create_NotificationOrderChain_WithSmsRecipient_WithReminders_V
             Assert.Equal(firstReminderOrderId, result[1].Id);
             Assert.Equal(secondReminderOrderId, result[2].Id);
 
-            string mainOrderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{mainOrderId}'";
             string mainOrdersChainSql = $@"SELECT count(*) FROM notifications.orderschain WHERE orderid = '{orderChainId}'";
-            string firstReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{firstReminderOrderId}'";
-            string secondReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{secondReminderOrderId}'";
+            string mainOrderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{mainOrderId}' and type ='Notification'";
+            string firstReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{firstReminderOrderId}' and type ='Reminder'";
+            string secondReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{secondReminderOrderId}' and type ='Reminder'";
             string firstSmsTextSql = $@"SELECT count(*) FROM notifications.smstexts as st JOIN notifications.orders o ON st._orderid = o._id WHERE o.alternateid = '{mainOrderId}'";
             string secondSmsTextSql = $@"SELECT count(*) FROM notifications.smstexts as st JOIN notifications.orders o ON st._orderid = o._id WHERE o.alternateid = '{mainOrderId}'";
 
@@ -534,6 +542,7 @@ public async Task Create_NotificationOrderChain_WithPersonRecipient_WithReminder
                 .SetOrderId(mainOrderId)
                 .SetOrderChainId(orderChainId)
                 .SetCreator(new Creator("ttd"))
+                .SetType(OrderType.Notification)
                 .SetRequestedSendTime(requestTime)
                 .SetSendersReference("ref-P5Q7R9S1")
                 .SetIdempotencyId("A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6")
@@ -568,6 +577,7 @@ public async Task Create_NotificationOrderChain_WithPersonRecipient_WithReminder
                     new NotificationReminder
                     {
                         DelayDays = 3,
+                        Type = OrderType.Reminder,
                         OrderId = firstReminderOrderId,
                         RequestedSendTime = requestTime.AddDays(3),
                         SendersReference = "ref-reminder-B4C6D8E0",
@@ -601,6 +611,7 @@ public async Task Create_NotificationOrderChain_WithPersonRecipient_WithReminder
                     new NotificationReminder
                     {
                         DelayDays = 7,
+                        Type = OrderType.Reminder,
                         OrderId = secondReminderOrderId,
                         RequestedSendTime = requestTime.AddDays(7),
                         SendersReference = "ref-reminder-F8G0H2I4",
@@ -640,6 +651,7 @@ public async Task Create_NotificationOrderChain_WithPersonRecipient_WithReminder
                 Creator = new("ttd"),
                 IgnoreReservation = true,
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestTime,
                 SendersReference = "ref-P5Q7R9S1",
                 ResourceId = "urn:altinn:resource:D208D0E6E5B4",
@@ -664,6 +676,7 @@ public async Task Create_NotificationOrderChain_WithPersonRecipient_WithReminder
                     IgnoreReservation = true,
                     Id = firstReminderOrderId,
                     Created = creationDateTime,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestTime.AddDays(3),
                     SendersReference = "ref-reminder-B4C6D8E0",
                     ResourceId = "urn:altinn:resource:D208D0E6E5B4",
@@ -685,6 +698,7 @@ public async Task Create_NotificationOrderChain_WithPersonRecipient_WithReminder
                     IgnoreReservation = false,
                     Created = creationDateTime,
                     Id = secondReminderOrderId,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestTime.AddDays(7),
                     SendersReference = "ref-reminder-F8G0H2I4",
                     ResourceId = "urn:altinn:resource:D208D0E6E5B4",
@@ -717,10 +731,10 @@ public async Task Create_NotificationOrderChain_WithPersonRecipient_WithReminder
             Assert.Equal(firstReminderOrderId, result[1].Id);
             Assert.Equal(secondReminderOrderId, result[2].Id);
 
-            string mainOrderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{mainOrderId}'";
             string mainOrdersChainSql = $@"SELECT count(*) FROM notifications.orderschain WHERE orderid = '{orderChainId}'";
-            string firstReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{firstReminderOrderId}'";
-            string secondReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{secondReminderOrderId}'";
+            string mainOrderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{mainOrderId}' and type = 'Notification'";
+            string firstReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{firstReminderOrderId}' and type = 'Reminder'";
+            string secondReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{secondReminderOrderId}' and type = 'Reminder'";
 
             int mainOrderCount = await PostgreUtil.RunSqlReturnOutput<int>(mainOrderSql);
             int firstReminderCount = await PostgreUtil.RunSqlReturnOutput<int>(firstReminderSql);
@@ -782,6 +796,7 @@ public async Task Create_NotificationOrderChain_WithOrganizationRecipient_WithRe
                 .SetOrderId(mainOrderId)
                 .SetOrderChainId(orderChainId)
                 .SetCreator(new Creator("ttd"))
+                .SetType(OrderType.Notification)
                 .SetRequestedSendTime(requestTime)
                 .SetSendersReference("ref-ORG-A2B4C6D8")
                 .SetIdempotencyId("E1F2G3H4-I5J6-K7L8-M9N0-O1P2Q3R4S5T6")
@@ -815,6 +830,7 @@ public async Task Create_NotificationOrderChain_WithOrganizationRecipient_WithRe
                     new NotificationReminder
                     {
                         DelayDays = 3,
+                        Type = OrderType.Reminder,
                         OrderId = firstReminderOrderId,
                         RequestedSendTime = requestTime.AddDays(3),
                         SendersReference = "ref-reminder-ORG-X2Y4Z6",
@@ -847,6 +863,7 @@ public async Task Create_NotificationOrderChain_WithOrganizationRecipient_WithRe
                     new NotificationReminder
                     {
                         DelayDays = 7,
+                        Type = OrderType.Reminder,
                         OrderId = secondReminderOrderId,
                         RequestedSendTime = requestTime.AddDays(7),
                         SendersReference = "ref-reminder-ORG-U2V4W6",
@@ -884,6 +901,7 @@ public async Task Create_NotificationOrderChain_WithOrganizationRecipient_WithRe
                 Id = mainOrderId,
                 Creator = new("ttd"),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestTime,
                 SendersReference = "ref-ORG-A2B4C6D8",
                 ResourceId = "urn:altinn:resource:T482D7F1A93C",
@@ -907,6 +925,7 @@ public async Task Create_NotificationOrderChain_WithOrganizationRecipient_WithRe
                     Creator = new("ttd"),
                     Id = firstReminderOrderId,
                     Created = creationDateTime,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestTime.AddDays(3),
                     SendersReference = "ref-reminder-ORG-X2Y4Z6",
                     ResourceId = "urn:altinn:resource:T482D7F1A93C",
@@ -927,6 +946,7 @@ public async Task Create_NotificationOrderChain_WithOrganizationRecipient_WithRe
                     Creator = new("ttd"),
                     Created = creationDateTime,
                     Id = secondReminderOrderId,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestTime.AddDays(7),
                     SendersReference = "ref-reminder-ORG-U2V4W6",
                     ResourceId = "urn:altinn:resource:T482D7F1A93C",
@@ -959,10 +979,10 @@ public async Task Create_NotificationOrderChain_WithOrganizationRecipient_WithRe
             Assert.Equal(firstReminderOrderId, result[1].Id);
             Assert.Equal(secondReminderOrderId, result[2].Id);
 
-            string mainOrderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{mainOrderId}'";
             string mainOrdersChainSql = $@"SELECT count(*) FROM notifications.orderschain WHERE orderid = '{orderChainId}'";
-            string firstReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{firstReminderOrderId}'";
-            string secondReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{secondReminderOrderId}'";
+            string mainOrderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{mainOrderId}' and type = 'Notification'";
+            string firstReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{firstReminderOrderId}' and type = 'Reminder'";
+            string secondReminderSql = $@"SELECT count(*) FROM notifications.orders WHERE alternateid = '{secondReminderOrderId}' and type = 'Reminder'";
 
             int mainOrderCount = await PostgreUtil.RunSqlReturnOutput<int>(mainOrderSql);
             int firstReminderCount = await PostgreUtil.RunSqlReturnOutput<int>(firstReminderSql);
@@ -1023,8 +1043,9 @@ public async Task Create_NotificationOrderChain_WithEmailRecipient_NoReminders_W
                 .SetOrderId(orderId)
                 .SetOrderChainId(orderChainId)
                 .SetCreator(new Creator("skd"))
-                .SetRequestedSendTime(requestedSendTime)
+                .SetType(OrderType.Notification)
                 .SetIdempotencyId("EXCEPTION-TEST-ID")
+                .SetRequestedSendTime(requestedSendTime)
                 .SetSendersReference("EXCEPTION-TEST-REF")
                 .SetRecipient(new NotificationRecipient
                 {
@@ -1049,6 +1070,7 @@ public async Task Create_NotificationOrderChain_WithEmailRecipient_NoReminders_W
                 Id = orderId,
                 Creator = new("skd"),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestedSendTime,
                 NotificationChannel = NotificationChannel.Email,
                 SendersReference = "EXCEPTION-TEST-REF",
@@ -1082,6 +1104,7 @@ public async Task Create_NotificationOrderChain_WithEmailRecipient_NoReminders_W
                 .SetOrderId(orderId)
                 .SetOrderChainId(orderChainId)
                 .SetCreator(new Creator("skd"))
+                .SetType(OrderType.Notification)
                 .SetRequestedSendTime(requestedSendTime)
                 .SetIdempotencyId("CANCELLATION-TEST-ID")
                 .SetSendersReference("CANCELLATION-TEST-REF")
@@ -1107,9 +1130,10 @@ public async Task Create_NotificationOrderChain_WithEmailRecipient_NoReminders_W
                 Id = orderId,
                 Creator = new("skd"),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestedSendTime,
-                NotificationChannel = NotificationChannel.Email,
                 SendersReference = "CANCELLATION-TEST-REF",
+                NotificationChannel = NotificationChannel.Email,
                 Templates =
                 [
                     new EmailTemplate("Email sender address", "Email subject", "Email body", EmailContentType.Plain)
@@ -1183,9 +1207,10 @@ public async Task GetOrderChainTracking_MainOrderWithoutSendersReference_Handles
             var orderChainRequest = new NotificationOrderChainRequest.NotificationOrderChainRequestBuilder()
                 .SetOrderId(orderId)
                 .SetOrderChainId(orderChainId)
+                .SetIdempotencyId(idempotencyId)
+                .SetType(OrderType.Notification)
                 .SetCreator(new Creator(creator))
                 .SetRequestedSendTime(requestedSendTime)
-                .SetIdempotencyId(idempotencyId)
                 .SetRecipient(new NotificationRecipient
                 {
                     RecipientEmail = new RecipientEmail
@@ -1208,6 +1233,7 @@ public async Task GetOrderChainTracking_MainOrderWithoutSendersReference_Handles
                 Id = orderId,
                 Creator = new(creator),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestedSendTime,
                 NotificationChannel = NotificationChannel.Email,
                 Templates =
@@ -1256,6 +1282,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderWithReminderMissing
                 .SetOrderId(mainOrderId)
                 .SetOrderChainId(orderChainId)
                 .SetIdempotencyId(idempotencyId)
+                .SetType(OrderType.Notification)
                 .SetCreator(new Creator(creator))
                 .SetRequestedSendTime(requestedSendTime)
                 .SetSendersReference("MAIN-ORDER-REF-NO-REMINDER-REF")
@@ -1280,6 +1307,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderWithReminderMissing
                     {
                         DelayDays = 3,
                         OrderId = reminderId,
+                        Type = OrderType.Reminder,
                         RequestedSendTime = requestedSendTime.AddDays(3),
                         Recipient = new NotificationRecipient
                         {
@@ -1306,6 +1334,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderWithReminderMissing
                 Id = mainOrderId,
                 Creator = new(creator),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestedSendTime,
                 NotificationChannel = NotificationChannel.Email,
                 SendersReference = "MAIN-ORDER-REF-NO-REMINDER-REF",
@@ -1327,6 +1356,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderWithReminderMissing
                     Id = reminderId,
                     Creator = new(creator),
                     Created = creationDateTime,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestedSendTime.AddDays(3),
                     NotificationChannel = NotificationChannel.Email,
                     Templates =
@@ -1384,6 +1414,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithRemindersE
                 .SetOrderChainId(orderChainId)
                 .SetIdempotencyId(idempotencyId)
                 .SetCreator(new Creator(creator))
+                .SetType(OrderType.Notification)
                 .SetSendersReference("MAIN-ORDER-REF")
                 .SetRequestedSendTime(requestedSendTime)
                 .SetRecipient(new NotificationRecipient
@@ -1407,6 +1438,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithRemindersE
                     {
                         DelayDays = 3,
                         OrderId = firstReminderId,
+                        Type = OrderType.Reminder,
                         SendersReference = "FIRST-REMINDER-REF",
                         RequestedSendTime = requestedSendTime.AddDays(3),
                         Recipient = new NotificationRecipient
@@ -1429,6 +1461,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithRemindersE
                     {
                         DelayDays = 7,
                         OrderId = secondReminderId,
+                        Type = OrderType.Reminder,
                         SendersReference = "SECOND-REMINDER-REF",
                         RequestedSendTime = requestedSendTime.AddDays(7),
                         Recipient = new NotificationRecipient
@@ -1456,6 +1489,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithRemindersE
                 Id = mainOrderId,
                 Creator = new(creator),
                 Created = creationDateTime,
+                Type = OrderType.Notification,
                 RequestedSendTime = requestedSendTime,
                 NotificationChannel = NotificationChannel.Email,
                 SendersReference = "MAIN-ORDER-REF",
@@ -1477,6 +1511,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithRemindersE
                     Id = firstReminderId,
                     Creator = new(creator),
                     Created = creationDateTime,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestedSendTime.AddDays(3),
                     NotificationChannel = NotificationChannel.Email,
                     SendersReference = "FIRST-REMINDER-REF",
@@ -1494,6 +1529,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithRemindersE
                     Id = secondReminderId,
                     Creator = new(creator),
                     Created = creationDateTime,
+                    Type = OrderType.Reminder,
                     RequestedSendTime = requestedSendTime.AddDays(7),
                     NotificationChannel = NotificationChannel.Email,
                     SendersReference = "SECOND-REMINDER-REF",
@@ -1556,6 +1592,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithoutReminde
                 .SetOrderChainId(orderChainId)
                 .SetIdempotencyId(idempotencyId)
                 .SetCreator(new Creator(creator))
+                .SetType(OrderType.Notification)
                 .SetRequestedSendTime(requestedSendTime)
                 .SetSendersReference("TRACKING-C69C615A8412")
                 .SetRecipient(new NotificationRecipient
@@ -1580,6 +1617,7 @@ public async Task GetOrderChainTracking_WhenNotificationOrderChainWithoutReminde
                 Id = orderId,
                 Creator = new(creator),
                 Created = creationDateTime,
+                Type = OrderType.Reminder,
                 RequestedSendTime = requestedSendTime,
                 NotificationChannel = NotificationChannel.Email,
                 SendersReference = "TRACKING-C69C615A8412",
diff --git a/test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs b/test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs
index 7870f5510..77adf9dbe 100644
--- a/test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs
+++ b/test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs
@@ -626,10 +626,10 @@ public async Task Post_MissingRecipients_ReturnsProblemDetails422Status()
         {
             ControllerContext = new ControllerContext { HttpContext = httpContext }
         };
-        
+
         // Act
         var result = await controller.Post(request);
-        
+
         // Assert
         var statusCodeResult = Assert.IsType<ObjectResult>(result.Result);
         var problemDetails = Assert.IsType<ProblemDetails>(statusCodeResult.Value);
@@ -789,6 +789,57 @@ public async Task Post_EnsuresCancellationTokenPassedToController_IsForwardedToA
         orderServiceMock.Verify(s => s.RegisterNotificationOrderChain(It.IsAny<NotificationOrderChainRequest>(), cancellationToken), Times.Once);
     }
 
+    [Fact]
+    public async Task Post_BuildThrowsInvalidOperationException_ReturnsBadRequestWithProblemDetails()
+    {
+        // Arrange
+        var request = new NotificationOrderChainRequestExt
+        {
+            // Setting the IdempotencyId to empty string intentionally to create a scenario where the validator passes but mapping fails.
+            IdempotencyId = string.Empty,
+            Recipient = new NotificationRecipientExt
+            {
+                RecipientEmail = new RecipientEmailExt
+                {
+                    EmailAddress = "test@example.com",
+                    Settings = new EmailSendingOptionsExt
+                    {
+                        Body = "Test body",
+                        Subject = "Test subject"
+                    }
+                }
+            }
+        };
+
+        var validatorMock = new Mock<IValidator<NotificationOrderChainRequestExt>>();
+        validatorMock.Setup(v => v.Validate(It.IsAny<NotificationOrderChainRequestExt>()))
+            .Returns(new ValidationResult()); // Return valid result to bypass validation
+
+        var orderServiceMock = new Mock<IOrderRequestService>();
+
+        var httpContext = new DefaultHttpContext();
+        httpContext.Items["Org"] = "ttd";
+
+        var controller = new FutureOrdersController(orderServiceMock.Object, validatorMock.Object)
+        {
+            ControllerContext = new ControllerContext { HttpContext = httpContext }
+        };
+
+        // Act
+        var result = await controller.Post(request);
+
+        // Assert
+        var objectResult = Assert.IsType<ObjectResult>(result.Result);
+        Assert.Equal(400, objectResult.StatusCode);
+
+        var problemDetails = Assert.IsType<ProblemDetails>(objectResult.Value);
+        Assert.Equal("Invalid notification order request", problemDetails.Title);
+        Assert.Equal(400, problemDetails.Status);
+        Assert.Contains("IdempotencyId must be set", problemDetails.Detail);
+
+        orderServiceMock.Verify(s => s.RegisterNotificationOrderChain(It.IsAny<NotificationOrderChainRequest>(), It.IsAny<CancellationToken>()), Times.Never);
+    }
+
     /// <summary>
     /// Creates a valid notification order chain request for testing.
     /// </summary>
@@ -876,10 +927,7 @@ private static async Task<HttpResponseMessage> SendPostRequest(HttpClient client
     /// <param name="reminderCount">The number of reminder shipments to include.</param>
     /// <param name="sendersReference">Custom sender's reference for the main notification.</param>
     /// <returns>A configured <see cref="NotificationOrderChainResponse"/> for testing.</returns>
-    private static NotificationOrderChainResponse CreateNotificationOrderChainResponse(
-        Guid orderId,
-        int reminderCount = 0,
-        string sendersReference = "notification-ref")
+    private static NotificationOrderChainResponse CreateNotificationOrderChainResponse(Guid orderId, int reminderCount = 0, string sendersReference = "notification-ref")
     {
         List<NotificationOrderChainShipment>? reminders = null;
 
@@ -915,9 +963,7 @@ private static NotificationOrderChainResponse CreateNotificationOrderChainRespon
     /// <param name="expectedResponse">Specific response to be returned by the mock service.</param>
     /// <param name="orderRequestService">Pre-configured order request service.</param>
     /// <returns>An HTTP client configured for testing.</returns>
-    private HttpClient GetTestClient(
-        NotificationOrderChainResponse? expectedResponse = null,
-        IOrderRequestService? orderRequestService = null)
+    private HttpClient GetTestClient(NotificationOrderChainResponse? expectedResponse = null, IOrderRequestService? orderRequestService = null)
     {
         if (orderRequestService == null)
         {
diff --git a/test/Altinn.Notifications.IntegrationTests/Notifications/OrdersController/OrdersControllerTests.cs b/test/Altinn.Notifications.IntegrationTests/Notifications/OrdersController/OrdersControllerTests.cs
index eee29f136..2b0cd02c6 100644
--- a/test/Altinn.Notifications.IntegrationTests/Notifications/OrdersController/OrdersControllerTests.cs
+++ b/test/Altinn.Notifications.IntegrationTests/Notifications/OrdersController/OrdersControllerTests.cs
@@ -56,7 +56,8 @@ public OrdersControllerTests(IntegrationTestWebApplicationFactory<Controllers.Or
             [],
             false,
             null,
-            null);
+            null,
+            OrderType.Notification);
 
         _orderWithStatus = new(
             _orderId,
@@ -68,7 +69,8 @@ public OrdersControllerTests(IntegrationTestWebApplicationFactory<Controllers.Or
             null,
             null,
             null,
-            new ProcessingStatus());
+            new ProcessingStatus(),
+            OrderType.Notification);
 
         _requestResponse = new()
         {
diff --git a/test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs b/test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs
index 694e6b56b..b783df3f9 100644
--- a/test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs
+++ b/test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs
@@ -26,6 +26,7 @@ public NotificationOrderTests()
         _order = new()
         {
             Id = id,
+            Type = OrderType.Notification,
             SendersReference = "senders-reference",
             Templates = new List<INotificationTemplate>()
             {
@@ -74,6 +75,7 @@ public NotificationOrderTests()
                 }
             },
             { "created", "2022-02-14T08:15:00Z" },
+            { "type", "Notification" },
             {
                 "templates",  new JsonArray()
                 {
@@ -142,16 +144,6 @@ public void SerializeToJson()
         Assert.Equal(expected, actual);
     }
 
-    [Theory]
-    [InlineData(1, "{ \"id\": \"4fec2be9-7f52-4d32-9554-467908c3c629\", \"created\": \"2023-07-14T07:39:19.088978Z\", \"creator\": { \"shortName\": \"ttd\" }, \"requestedSendTime\": \"2023-08-14T08:15:00Z\", \"templates\": [ { \"$\": \"email\", \"body\": \"email-body\", \"type\": \"Email\", \"subject\": \"email-subject\", \"contentType\": \"Html\", \"fromAddress\": \"sender@domain.com\" } ], \"recipients\": [ { \"addressInfo\": [ { \"$\": \"email\", \"addressType\": \"Email\", \"emailAddress\": \"recipient1@domain.com\" } ], \"recipientId\": \"\" }, { \"addressInfo\": [ { \"$\": \"email\", \"addressType\": \"Email\", \"emailAddress\": \"recipient2@domain.com\" } ], \"recipientId\": \"\" } ], \"sendersReference\": \"senders-reference\", \"notificationChannel\": \"Email\" }")]
-#pragma warning disable xUnit1026, IDE0060// Theory methods should use all of their parameters and Remove unused parameter
-    public void Deserialize(int exampleNo, string serializedOrder)
-#pragma warning restore xUnit1026, IDE0060
-    {
-        var actual = NotificationOrder.Deserialize(serializedOrder);
-        Assert.NotNull(actual);
-    }
-
     [Fact]
     public void TryParse_EmptyString_False()
     {
diff --git a/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs b/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs
index 6332ddb79..189cdb9f9 100644
--- a/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs
+++ b/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs
@@ -40,6 +40,7 @@ public async Task RegisterNotificationOrder_ForEmail_ExpectedInputToRepository()
             Id = id,
             Created = createdTime,
             Creator = new("ttd"),
+            Type = OrderType.Notification,
             NotificationChannel = NotificationChannel.Email,
             RequestedSendTime = sendTime,
             Recipients = { },
@@ -87,6 +88,7 @@ public async Task RegisterNotificationOrder_ForEmail_NoFromAddressDefaultInserte
             Id = id,
             Created = createdTime,
             Creator = new("ttd"),
+            Type = OrderType.Notification,
             NotificationChannel = NotificationChannel.Email,
             RequestedSendTime = sendTime,
             Recipients = { },
@@ -134,6 +136,7 @@ public async Task RegisterNotificationOrder_ForSms_ExpectedInputToRepository()
             Id = id,
             Created = createdTime,
             Creator = new("ttd"),
+            Type = OrderType.Notification,
             NotificationChannel = NotificationChannel.Sms,
             RequestedSendTime = sendTime,
             Recipients = { },
@@ -181,6 +184,7 @@ public async Task RegisterNotificationOrder_ForSms_NoSenderNumberDefaultInserted
             Id = id,
             Created = createdTime,
             Creator = new("ttd"),
+            Type = OrderType.Notification,
             NotificationChannel = NotificationChannel.Sms,
             RequestedSendTime = sendTime,
             Recipients = { },
@@ -262,6 +266,7 @@ public async Task RegisterNotificationOrder_ForSms_LookupPartialSuccess_OrderCre
             Id = id,
             Created = createdTime,
             Creator = new("ttd"),
+            Type = OrderType.Notification,
             NotificationChannel = NotificationChannel.Sms,
             RequestedSendTime = sendTime,
             Recipients = [
@@ -334,6 +339,7 @@ public async Task RegisterNotificationOrder_ForSms_LookupSuccess_OrderCreated()
             Id = id,
             Created = createdTime,
             Creator = new("ttd"),
+            Type = OrderType.Notification,
             NotificationChannel = NotificationChannel.Sms,
             RequestedSendTime = sendTime,
             Recipients = [
@@ -631,10 +637,6 @@ public async Task RegisterNotificationOrder_ForEmailAndSms_CallsAddEmailAndSmsCo
         repoMock.Verify(r => r.Create(It.IsAny<NotificationOrder>()), Times.Once);
     }
 
-    /// <summary>
-    /// This test verifies that the service returns a ServiceError when contact information is missing.
-    /// </summary>
-    /// <returns>An asyn task</returns>
     [Fact]
     public async Task RegisterNotificationOrderChain_ShouldReturnServiceError_WhenMissingContactInformation()
     {
@@ -646,8 +648,9 @@ public async Task RegisterNotificationOrderChain_ShouldReturnServiceError_WhenMi
         var orderChainRequest = new NotificationOrderChainRequest.NotificationOrderChainRequestBuilder()
             .SetOrderId(orderId)
             .SetOrderChainId(orderChainId)
-            .SetIdempotencyId("idempotencyMockId")
             .SetCreator(new Creator("brg"))
+            .SetType(OrderType.Notification)
+            .SetIdempotencyId("idempotencyMockId")
             .SetRecipient(new NotificationRecipient
             {
                 RecipientOrganization = new RecipientOrganization
@@ -696,10 +699,6 @@ public async Task RegisterNotificationOrderChain_ShouldReturnServiceError_WhenMi
             });
     }
 
-    /// <summary>
-    /// This test verifies that the service returns a ServiceError when contact information is missing for a reminder.
-    /// </summary>
-    /// <returns>An asyn task</returns>
     [Fact]
     public async Task RegisterNotificationOrderChain_ShouldReturnServiceError_WhenMissingContactInformationForReminder()
     {
@@ -711,8 +710,9 @@ public async Task RegisterNotificationOrderChain_ShouldReturnServiceError_WhenMi
         var orderChainRequest = new NotificationOrderChainRequest.NotificationOrderChainRequestBuilder()
             .SetOrderId(orderId)
             .SetOrderChainId(orderChainId)
-            .SetIdempotencyId("idempotencyMockId")
             .SetCreator(new Creator("brg"))
+            .SetType(OrderType.Notification)
+            .SetIdempotencyId("idempotencyMockId")
             .SetRecipient(new NotificationRecipient
             {
                 RecipientOrganization = new RecipientOrganization
@@ -735,12 +735,13 @@ public async Task RegisterNotificationOrderChain_ShouldReturnServiceError_WhenMi
                 new()
                 {
                     DelayDays = 7,
+                    Type = OrderType.Reminder,
                     Recipient = new NotificationRecipient
                     {
                         RecipientOrganization = new RecipientOrganization
                         {
-                            ChannelSchema = NotificationChannel.Email,
                             OrgNumber = "312508730",
+                            ChannelSchema = NotificationChannel.Email,
                             ResourceId = "urn:altinn:resource:email-sms-resource-name",
                             EmailSettings = new EmailSendingOptions
                             {
@@ -809,6 +810,7 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
             .SetOrderId(mainOrderId)
             .SetOrderChainId(orderChainId)
             .SetCreator(new Creator("skd"))
+            .SetType(OrderType.Notification)
             .SetSendersReference("TAX-REMINDER-2025")
             .SetRequestedSendTime(mainOrderSendTime.AddDays(1))
             .SetIdempotencyId("84CD3017-92E3-4C3D-80DE-C10338F30813")
@@ -845,6 +847,7 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
                 {
                     DelayDays = 7,
                     OrderId = firstReminderId,
+                    Type = OrderType.Reminder,
                     SendersReference = "TAX-REMINDER-2025-FIRST",
                     RequestedSendTime = mainOrderSendTime.AddDays(7),
                     ConditionEndpoint = new Uri("https://api.skatteetaten.no/conditions/incomplete"),
@@ -877,6 +880,7 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
                 {
                     DelayDays = 14,
                     OrderId = secondReminderId,
+                    Type = OrderType.Reminder,
                     SendersReference = "TAX-REMINDER-2025-FINAL",
                     RequestedSendTime = mainOrderSendTime.AddDays(14),
                     ConditionEndpoint = new Uri("https://api.Skatteetaten.no/conditions/incomplete"),
@@ -923,7 +927,8 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
             [new([], "29105573746")],
             true,
             resourceId,
-            new Uri("https://api.skatteetaten.no/conditions/new"));
+            new Uri("https://api.skatteetaten.no/conditions/new"),
+            OrderType.Notification);
 
         var expectedFirstReminder = new NotificationOrder(
             firstReminderId,
@@ -939,7 +944,8 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
             [new([], "29105573746")],
             true,
             resourceId,
-            new Uri("https://api.skatteetaten.no/conditions/incomplete"));
+            new Uri("https://api.skatteetaten.no/conditions/incomplete"),
+            OrderType.Reminder);
 
         var expectedFinalReminder = new NotificationOrder(
             secondReminderId,
@@ -955,7 +961,8 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
             [new([], "29105573746")],
             true,
             resourceId,
-            new Uri("https://api.Skatteetaten.no/conditions/incomplete"));
+            new Uri("https://api.Skatteetaten.no/conditions/incomplete"),
+            OrderType.Reminder);
 
         var orderRepositoryMock = new Mock<IOrderRepository>();
         var contactPointServiceMock = new Mock<IContactPointService>();
@@ -1027,10 +1034,12 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
                         It.Is<NotificationOrderChainRequest>(req =>
                             req.OrderChainId == orderChainId &&
                             req.DialogportenAssociation != null &&
+                            req.Type == OrderType.Notification &&
                             req.DialogportenAssociation.DialogId == "20E3D06D5546" &&
                             req.DialogportenAssociation.TransmissionId == "F9D34BB1C65F"),
                         It.Is<NotificationOrder>(o =>
                             o.Id == mainOrderId &&
+                            o.Type == OrderType.Notification &&
                             o.SendersReference == "TAX-REMINDER-2025" &&
                             o.ResourceId == resourceId &&
                             o.NotificationChannel == NotificationChannel.EmailPreferred &&
@@ -1038,7 +1047,9 @@ public async Task RegisterNotificationOrderChain_RecipientPersonWithMultipleRemi
                         It.Is<List<NotificationOrder>>(list =>
                             list.Count == 2 &&
                             list[0].Id == firstReminderId &&
-                            list[1].Id == secondReminderId),
+                            list[1].Id == secondReminderId &&
+                            list[0].Type == OrderType.Reminder &&
+                            list[1].Type == OrderType.Reminder),
                         It.IsAny<CancellationToken>()),
                     Times.Once);
 
@@ -1081,6 +1092,7 @@ public async Task RegisterNotificationOrderChain_RecipientOrganizationWithEmailA
             .SetOrderId(orderId)
             .SetOrderChainId(orderChainId)
             .SetCreator(new Creator("brg"))
+            .SetType(OrderType.Notification)
             .SetSendersReference("REF-42DBDAB8281C")
             .SetRequestedSendTime(currentTime.AddHours(2))
             .SetIdempotencyId("A5B28914-7056-4E3B-9DAF-BEA23321D39C")
@@ -1127,7 +1139,8 @@ public async Task RegisterNotificationOrderChain_RecipientOrganizationWithEmailA
             [new([], organizationNumber: "312508729")],
             null,
             "urn:altinn:resource:email-sms-resource-name",
-            new Uri("https://api.brreg.no/conditions/notification"));
+            new Uri("https://api.brreg.no/conditions/notification"),
+            OrderType.Notification);
 
         var orderRepositoryMock = new Mock<IOrderRepository>();
         orderRepositoryMock.Setup(r => r.Create(
@@ -1170,6 +1183,7 @@ public async Task RegisterNotificationOrderChain_RecipientOrganizationWithEmailA
                     It.Is<NotificationOrderChainRequest>(e => e.OrderChainId == orderChainId),
                     It.Is<NotificationOrder>(o =>
                         o.Id == orderId &&
+                        o.Type == OrderType.Notification &&
                         o.SendersReference == "REF-42DBDAB8281C" &&
                         o.SendingTimePolicy == SendingTimePolicy.Daytime &&
                         o.NotificationChannel == NotificationChannel.EmailAndSms &&
@@ -1206,6 +1220,7 @@ public async Task RegisterNotificationOrderChain_RepositoryReturnsEmptyList_Retu
             .SetOrderId(orderId)
             .SetOrderChainId(orderChainId)
             .SetCreator(new Creator("test"))
+            .SetType(OrderType.Notification)
             .SetIdempotencyId("test-idempotency-id")
             .SetRecipient(new NotificationRecipient
             {
@@ -1261,6 +1276,7 @@ public async Task RegisterNotificationOrderChain_WhenCancellationRequested_Throw
             .SetOrderId(mainOrderId)
             .SetOrderChainId(orderChainId)
             .SetCreator(new Creator("test"))
+            .SetType(OrderType.Notification)
             .SetIdempotencyId("test-cancellation-id")
             .SetRequestedSendTime(mainOrderSendTime.AddDays(1))
             .SetRecipient(new NotificationRecipient
@@ -1307,6 +1323,74 @@ public async Task RegisterNotificationOrderChain_WhenCancellationRequested_Throw
             Times.Never);
     }
 
+    [Fact]
+    public async Task RegisterNotificationOrderChain_WithMissingSmsContactInformation_ReturnsServiceError()
+    {
+        // Arrange
+        Guid orderId = Guid.NewGuid();
+        Guid orderChainId = Guid.NewGuid();
+        DateTime currentTime = DateTime.UtcNow;
+
+        var orderChainRequest = new NotificationOrderChainRequest.NotificationOrderChainRequestBuilder()
+            .SetOrderId(orderId)
+            .SetOrderChainId(orderChainId)
+            .SetCreator(new Creator("skd"))
+            .SetType(OrderType.Notification)
+            .SetIdempotencyId("sms-missing-contact-test-id")
+            .SetRecipient(new NotificationRecipient
+            {
+                RecipientPerson = new RecipientPerson
+                {
+                    NationalIdentityNumber = "16069412345",
+                    ChannelSchema = NotificationChannel.Sms,
+                    ResourceId = "urn:altinn:resource:sms-test",
+                    SmsSettings = new SmsSendingOptions
+                    {
+                        Body = "Test SMS body",
+                        Sender = "TestSender"
+                    }
+                }
+            })
+            .Build();
+
+        var orderRepositoryMock = new Mock<IOrderRepository>();
+        var contactPointServiceMock = new Mock<IContactPointService>();
+        contactPointServiceMock
+            .Setup(contactService => contactService.AddSmsContactPoints(It.IsAny<List<Recipient>>(), It.IsAny<string?>()))
+            .Callback<List<Recipient>, string?>((recipients, _) =>
+            {
+                // Intentionally don't add SMS contact point to simulate missing contact
+            });
+
+        var service = GetTestService(orderRepositoryMock.Object, contactPointServiceMock.Object, orderId, currentTime);
+
+        // Act
+        Result<NotificationOrderChainResponse, ServiceError> result = await service.RegisterNotificationOrderChain(orderChainRequest);
+
+        // Assert
+        result.Match(
+            success =>
+            {
+                Assert.Fail("Expected error but got success result instead");
+                return false;
+            },
+            error =>
+            {
+                Assert.IsType<ServiceError>(result.Error);
+                Assert.Equal(422, error.ErrorCode);
+                Assert.Equal("Missing contact information for recipient(s): 16069412345", error.ErrorMessage);
+
+                // Verify the contact point service was called with SMS channel
+                contactPointServiceMock.Verify(
+                    cp => cp.AddSmsContactPoints(
+                        It.Is<List<Recipient>>(r => r.Any(rec => rec.NationalIdentityNumber == "16069412345")),
+                        It.Is<string?>(s => s == "sms-test")),
+                    Times.Once);
+
+                return true;
+            });
+    }
+
     [Fact]
     public async Task RetrieveOrderChainTracking_WhenCancellationRequested_ThrowsOperationCanceledException()
     {
@@ -1567,6 +1651,7 @@ public async Task CreateNotificationOrder_WithMissingContactInformation_ReturnsS
                     .SetRecipient(recipient)
                     .SetOrderChainId(orderChainId)
                     .SetCreator(new Creator("test"))
+                    .SetType(OrderType.Notification)
                     .SetRequestedSendTime(currentTime.AddHours(1))
                     .SetIdempotencyId("C0A3FABE-D65F-48A0-8745-5D4CC6EA7968")
                     .Build());
@@ -1639,9 +1724,10 @@ public async Task CreateNotificationOrder_PassesCorrectValueForSendingTimePolicy
         await service.RegisterNotificationOrderChain(
             new NotificationOrderChainRequest.NotificationOrderChainRequestBuilder()
                 .SetOrderId(orderId)
-                .SetOrderChainId(orderChainId)
                 .SetRecipient(recipient)
+                .SetOrderChainId(orderChainId)
                 .SetCreator(new Creator("test"))
+                .SetType(OrderType.Notification)
                 .SetRequestedSendTime(currentTime.AddHours(1))
                 .SetIdempotencyId("C0A3FABE-D65F-48A0-8745-5D4CC6EA7968")
                 .Build());
diff --git a/test/Altinn.Notifications.Tests/Notifications/TestingMappers/NotificationOrderChainMapperTests.cs b/test/Altinn.Notifications.Tests/Notifications/TestingMappers/NotificationOrderChainMapperTests.cs
index 5b3f3aac8..84dbabf94 100644
--- a/test/Altinn.Notifications.Tests/Notifications/TestingMappers/NotificationOrderChainMapperTests.cs
+++ b/test/Altinn.Notifications.Tests/Notifications/TestingMappers/NotificationOrderChainMapperTests.cs
@@ -57,6 +57,7 @@ public void MapToNotificationOrderChainRequest_WithEmailRecipientAndDialogporten
         // Verify NotificationOrderChainRequest properties
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-AB12CD34", result.SendersReference);
@@ -171,6 +172,7 @@ public void MapToNotificationOrderChainRequest_WithEmailRecipientAndMultipleRemi
         // Verify NotificationOrderChainRequest properties
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-D1E4B80C", result.SendersReference);
@@ -198,6 +200,7 @@ public void MapToNotificationOrderChainRequest_WithEmailRecipientAndMultipleRemi
         var firstReminder = result.Reminders[0];
         Assert.Equal(3, firstReminder.DelayDays);
         Assert.NotEqual(Guid.Empty, firstReminder.OrderId);
+        Assert.Equal(OrderType.Reminder, firstReminder.Type);
         Assert.NotEqual(result.OrderId, firstReminder.OrderId);
         Assert.NotEqual(result.OrderChainId, firstReminder.OrderId);
         Assert.Equal("12236E1A-C7D9-4334-8CEE-873DAA64467F", firstReminder.SendersReference);
@@ -223,6 +226,7 @@ public void MapToNotificationOrderChainRequest_WithEmailRecipientAndMultipleRemi
         var secondReminder = result.Reminders[1];
         Assert.Equal(5, secondReminder.DelayDays);
         Assert.NotEqual(Guid.Empty, secondReminder.OrderId);
+        Assert.Equal(OrderType.Reminder, secondReminder.Type);
         Assert.NotEqual(result.OrderId, secondReminder.OrderId);
         Assert.NotEqual(result.OrderChainId, secondReminder.OrderId);
         Assert.Equal("7B1A786D-4767-4113-8401-836D1D176BC2", secondReminder.SendersReference);
@@ -287,6 +291,7 @@ public void MapToNotificationOrderChainRequest_WithEmailRecipientAndNoReminders_
         // Verify NotificationOrderChainRequest properties
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-D1E4B80C", result.SendersReference);
@@ -393,6 +398,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientEmailCha
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal(requestExt.ConditionEndpoint, result.ConditionEndpoint);
@@ -474,6 +480,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientEmailPre
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-4617F6FFBE7D", result.SendersReference);
@@ -612,6 +619,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientEmailPre
         // Main order verification
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal(baseTime.ToUniversalTime(), result.RequestedSendTime);
         Assert.Equal("4567890A-BCDE-F123-4567-89ABCDEF1234", result.SendersReference);
@@ -643,6 +651,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientEmailPre
         // First reminder verification
         var firstReminder = result.Reminders[0];
         Assert.Equal(3, firstReminder.DelayDays);
+        Assert.Equal(OrderType.Reminder, firstReminder.Type);
         Assert.Equal("5C6D7E8F-9A0B-1C2D-3E4F-5A6B7C8D9E0F", firstReminder.SendersReference);
         Assert.Equal(requestExt.Reminders[0].ConditionEndpoint, firstReminder.ConditionEndpoint);
 
@@ -678,6 +687,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientEmailPre
         // Second reminder verification
         var secondReminder = result.Reminders[1];
         Assert.Equal(7, secondReminder.DelayDays);
+        Assert.Equal(OrderType.Reminder, secondReminder.Type);
         Assert.Equal("1C2D3E4F-5A6B-7C8D-9E0F-1A2B3C4D5E6F", secondReminder.SendersReference);
         Assert.Equal(requestExt.Reminders[1].ConditionEndpoint, secondReminder.ConditionEndpoint);
 
@@ -756,6 +766,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientSmsPrefe
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-4617F6FFBE7D", result.SendersReference);
@@ -892,6 +903,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientSmsPrefe
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal("ref-F1E2D3C4B5A6", result.SendersReference);
         Assert.Equal(baseTime.ToUniversalTime(), result.RequestedSendTime);
 
@@ -922,6 +934,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientSmsPrefe
         // First reminder verification
         var firstReminder = result.Reminders[0];
         Assert.Equal(3, firstReminder.DelayDays);
+        Assert.Equal(OrderType.Reminder, firstReminder.Type);
         Assert.Equal("ref-A1B2C3D4E5F6", firstReminder.SendersReference);
         Assert.Equal(requestExt.Reminders[0].ConditionEndpoint, firstReminder.ConditionEndpoint);
 
@@ -948,6 +961,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationRecipientSmsPrefe
         // Second reminder verification
         var secondReminder = result.Reminders[1];
         Assert.Equal(7, secondReminder.DelayDays);
+        Assert.Equal(OrderType.Reminder, secondReminder.Type);
         Assert.Equal("ref-G1H2I3J4K5L6", secondReminder.SendersReference);
         Assert.Equal(requestExt.Reminders[1].ConditionEndpoint, secondReminder.ConditionEndpoint);
 
@@ -1011,6 +1025,7 @@ public void MapToNotificationOrderChainRequest_WithOrganizationUsingRecipientSms
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-9B8D303243B6", result.SendersReference);
@@ -1123,6 +1138,7 @@ public void MapToNotificationOrderChainRequest_WithSmsRecipientAndMultipleRemind
         // Verify NotificationOrderChainRequest properties
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-D3C9BA54", result.SendersReference);
@@ -1148,6 +1164,7 @@ public void MapToNotificationOrderChainRequest_WithSmsRecipientAndMultipleRemind
         var firstReminder = result.Reminders[0];
         Assert.Equal(3, firstReminder.DelayDays);
         Assert.NotEqual(Guid.Empty, firstReminder.OrderId);
+        Assert.Equal(OrderType.Reminder, firstReminder.Type);
         Assert.NotEqual(result.OrderId, firstReminder.OrderId);
         Assert.NotEqual(result.OrderChainId, firstReminder.OrderId);
         Assert.Equal("ref-reminder-A3BCFE4284D6", firstReminder.SendersReference);
@@ -1172,6 +1189,7 @@ public void MapToNotificationOrderChainRequest_WithSmsRecipientAndMultipleRemind
         var secondReminder = result.Reminders[1];
         Assert.Equal(7, secondReminder.DelayDays);
         Assert.NotEqual(Guid.Empty, secondReminder.OrderId);
+        Assert.Equal(OrderType.Reminder, secondReminder.Type);
         Assert.NotEqual(result.OrderId, secondReminder.OrderId);
         Assert.NotEqual(result.OrderChainId, secondReminder.OrderId);
         Assert.Equal("ref-reminder-F2491E785C2D", secondReminder.SendersReference);
@@ -1232,6 +1250,7 @@ public void MapToNotificationOrderChainRequest_WithSmsRecipientAndNoReminders_Ma
         // Verify NotificationOrderChainRequest properties
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-4617F6FFBE7D", result.SendersReference);
@@ -1298,6 +1317,7 @@ public void MapToNotificationOrderChainRequest_WithoutRequestedSendTime_UsesCurr
         // Verify other properties are correctly mapped
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("BC47D9EA-3CD5-48A6-B5B7-CF5B95D53F9B", result.IdempotencyId);
@@ -1349,6 +1369,7 @@ public void MapToNotificationOrderChainRequest_WithPersonRecipientEmailChannel_M
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal(requestExt.ConditionEndpoint, result.ConditionEndpoint);
@@ -1421,6 +1442,7 @@ public void MapToNotificationOrderChainRequest_WithPersonRecipientSmsChannel_Map
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-9B8D303243B6", result.SendersReference);
@@ -1500,6 +1522,7 @@ public void MapToNotificationOrderChainRequest_WithPersonRecipientEmailPreferred
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.Equal(creatorName, result.Creator.ShortName);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-4617F6FFBE7D", result.SendersReference);
@@ -1643,6 +1666,7 @@ public void MapToNotificationOrderChainRequest_WithPersonRecipientEmailPreferred
         Assert.NotNull(result);
         Assert.NotEqual(Guid.Empty, result.OrderId);
         Assert.NotEqual(Guid.Empty, result.OrderChainId);
+        Assert.Equal(OrderType.Notification, result.Type);
         Assert.NotEqual(result.OrderId, result.OrderChainId);
         Assert.Equal("ref-F1E2D3C4B5A6", result.SendersReference);
         Assert.Equal(baseTime.ToUniversalTime(), result.RequestedSendTime);
@@ -1675,6 +1699,7 @@ public void MapToNotificationOrderChainRequest_WithPersonRecipientEmailPreferred
         // First reminder verification
         var firstReminder = result.Reminders[0];
         Assert.Equal(3, firstReminder.DelayDays);
+        Assert.Equal(OrderType.Reminder, firstReminder.Type);
         Assert.Equal("ref-A1B2C3D4E5F6", firstReminder.SendersReference);
         Assert.Equal(requestExt.Reminders[0].ConditionEndpoint, firstReminder.ConditionEndpoint);
 
@@ -1702,6 +1727,7 @@ public void MapToNotificationOrderChainRequest_WithPersonRecipientEmailPreferred
         // Second reminder verification
         var secondReminder = result.Reminders[1];
         Assert.Equal(7, secondReminder.DelayDays);
+        Assert.Equal(OrderType.Reminder, secondReminder.Type);
         Assert.Equal("ref-G1H2I3J4K5L6", secondReminder.SendersReference);
         Assert.Equal(requestExt.Reminders[1].ConditionEndpoint, secondReminder.ConditionEndpoint);
 
@@ -1901,4 +1927,20 @@ public void Build_WithEmptyCreatorName_ThrowsInvalidOperationException()
         // Act & Assert
         Assert.Throws<InvalidOperationException>(() => builder.Build());
     }
+
+    [Fact]
+    public void Build_WithInvalidOrderType_ThrowsInvalidOperationException()
+    {
+        // Arrange
+        var builder = new NotificationOrderChainRequest.NotificationOrderChainRequestBuilder()
+            .SetOrderId(Guid.NewGuid())
+            .SetType(OrderType.Reminder)
+            .SetCreator(new Creator("ttd"))
+            .SetOrderChainId(Guid.NewGuid())
+            .SetRecipient(new NotificationRecipient())
+            .SetIdempotencyId("A58AD811-4DEB-4B05-B5C9-89AD3A4BD20F");
+
+        // Act & Assert
+        Assert.Throws<InvalidOperationException>(() => builder.Build());
+    }
 }


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 0eeed95089338fb4be2c1811f8f69977e4abf5c0 and 33fe244d3bf8f8d558a273d6c0e450f4f5e6e2d6.

</details>

<details>
<summary>📒 Files selected for processing (16)</summary>

* `src/Altinn.Notifications.Core/Enums/OrderTypes.cs` (1 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs` (1 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs` (1 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs` (5 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs` (1 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs` (2 hunks)
* `src/Altinn.Notifications.Core/Services/OrderRequestService.cs` (5 hunks)
* `src/Altinn.Notifications.Persistence/Altinn.Notifications.Persistence.csproj` (1 hunks)
* `src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/getshipmenttracking.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Repository/NotificationDeliveryManifestRepository.cs` (5 hunks)
* `src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs` (3 hunks)
* `src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs` (2 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Analyze (csharp)
* GitHub Check: Build, test & analyze

</details>

<details>
<summary>🔇 Additional comments (36)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Persistence/Altinn.Notifications.Persistence.csproj (1)</summary>

`45-45`: **No functional changes detected.**  
The added line is only trailing whitespace and does not impact the project’s build or behavior.

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs (1)</summary>

`55-58`: **LGTM!**

The addition of the `Type` property to the interface with proper documentation looks good.

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs (1)</summary>

`104-107`: **Verify Type property handling during deserialization**

The deserialization logic should handle the new `Type` property correctly. While JsonSerializer will typically handle this automatically, it's worth verifying that deserialized objects have the correct Type value, especially if the property isn't explicitly handled.


Consider adding a unit test that verifies the `Type` property is correctly preserved through serialization and deserialization.

</details>
<details>
<summary>src/Altinn.Notifications.Core/Enums/OrderTypes.cs (1)</summary>

`1-17`: **LGTM: Well-structured enum implementation**

The `OrderTypes` enum is properly implemented with good documentation and explicit values that align with the business domain requirements. Having this typed enumeration will improve type safety throughout the codebase.

</details>
<details>
<summary>src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql (1)</summary>

`1-9`: **Good use of idempotent migration script**

The script correctly implements a conditional check before creating the new enum type, which makes the migration idempotent. This approach prevents errors when running migrations multiple times, which is essential for robust deployment processes.

</details>
<details>
<summary>src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs (2)</summary>

`55-55`: **Properly setting notification type in builder**

The notification type is correctly set to `OrderTypes.Notification` in the chain request builder, which aligns with the PR objective to display the correct type.

---

`111-111`: **Properly setting reminder type**

The reminder type is correctly set to `OrderTypes.Reminder` in the object initialization, ensuring consistent type classification throughout the system.

</details>
<details>
<summary>src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql (1)</summary>

`1-12`: **Well-designed table alteration script**

The script follows good practices with:
1. A conditional check to prevent duplicate modifications
2. Appropriate NOT NULL constraint with a default value
3. Proper use of the enum type created in the previous migration

This approach ensures compatibility with existing data while enforcing type safety for new records.

</details>
<details>
<summary>src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs (3)</summary>

`28-28`: **Comment updated to document new type parameter**

The SQL statement comment has been correctly updated to include the new type parameter, helping future developers understand the parameter structure.

---

`394-394`: **Modern C# syntax improvement**

Using target-typed `new` syntax simplifies the code and improves readability.

---

`403-403`: **Order type parameter correctly added**

The order type parameter is correctly implemented:
1. Uses the appropriate NpgsqlDbType
2. Converts the enum to string using ToString()
3. Matches the database's expected parameter order

This ensures the correct order type is stored in the database.

</details>
<details>
<summary>src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql (1)</summary>

`41-67`: **Function overload implementation looks good!**

The new function overload properly supports the order type feature by:
1. Accepting the `_type` parameter as text
2. Properly casting it to the PostgreSQL enum type `public.notificationordertypes`
3. Maintaining consistent attributes (language, cost, volatility, parallel safety)

This implementation ensures backward compatibility while enabling type distinction between notifications and reminders.

</details>
<details>
<summary>src/Altinn.Notifications.Persistence/Repository/NotificationDeliveryManifestRepository.cs (5)</summary>

`22-22`: **Appropriate constant name for type column.**

The constant follows the established naming pattern and will make future references to this column consistent throughout the code.

---

`28-28`: **Updated function reference to new version.**

Correctly updated to use the new `get_shipment_tracking_v2` function that supports the order type distinction.

---

`109-118`: **Well-implemented helper method for type extraction.**

The `GetType` method follows the same pattern as other similar methods in this class, extracting the type value from the database record using the column name constant.

---

`304-305`: **Correctly retrieves order type from database record.**

The code now properly retrieves the order type from the database record instead of hardcoding it, ensuring accurate type classification in the delivery manifest.

---

`317-317`: **Type property correctly propagated to the delivery manifest.**

The type information is properly passed to the `NotificationDeliveryManifest` constructor, fulfilling the PR objective to display the correct notification type.

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs (5)</summary>

`1-2`: **Appropriate using directives for the OrderTypes enum.**

The code correctly imports the `Altinn.Notifications.Core.Enums` namespace for the new `OrderTypes` enum.

---

`99-106`: **Well-documented Type property.**

The Type property is properly documented with XML comments that clearly explain its purpose and usage.

---

`124-134`: **Builder pattern correctly extended for Type property.**

The implementation follows the established builder pattern, allowing fluent setting of the Type property.

---

`230-234`: **Important validation ensures correct type usage.**

The validation check ensures that only orders of type `OrderTypes.Notification` can be built using this builder, preventing misuse of the API.

---

`257-257`: **Type property correctly included in constructed object.**

The type value is properly assigned to the constructed NotificationOrderChainRequest object.

</details>
<details>
<summary>src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/getshipmenttracking.sql (7)</summary>

`78-79`: **Clear comment for the new function.**

The comment clearly indicates that this is a new version of the function that returns the notification type.

---

`80-88`: **Function signature properly extended with type column.**

The function signature is correctly extended to include the additional `type` column of TEXT type, allowing for proper type information retrieval.

---

`108-109`: **The order data query correctly includes the type column.**

The order_data CTE now properly includes the type column from the orders table, making it available for the rest of the query.

---

`117-119`: **Type correctly included in order tracking.**

The order tracking CTE properly includes the type column cast to TEXT, ensuring consistent type representation.

---

`126-128`: **Type correctly included in email tracking.**

The email tracking CTE properly includes the type column from the order data, ensuring that email notifications carry the correct type information.

---

`136-138`: **Type correctly included in SMS tracking.**

The SMS tracking CTE properly includes the type column from the order data, ensuring that SMS notifications carry the correct type information.

---

`149-157`: **Function documentation updated.**

The documentation for the new function correctly describes its purpose and the data it returns.

</details>
<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (5)</summary>

`100-101`: **Properly propagating the order type to CreateNotificationOrder**

The type property is now correctly passed from the order request to the CreateNotificationOrder method, ensuring the order type metadata flows properly through the system.

---

`164-166`: **Well-documented parameter**

Good documentation for the new orderType parameter, clearly explaining its purpose in the method.

---

`177-178`: **Method signature properly updated**

The method signature has been correctly updated to include the OrderTypes parameter, ensuring type information is captured during order creation.

---

`202-203`: **Order type correctly assigned**

The Type property of the NotificationOrder is properly set to the passed orderType parameter, ensuring the classification is preserved in the model.

---

`417-418`: **Reminder type property properly passed**

The Type property from the reminder is correctly passed to the CreateNotificationOrder method, maintaining the distinction between notification types throughout the process.

</details>
<details>
<summary>src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql (2)</summary>

`465-544`: **New function properly implements type-aware tracking**

The new `get_shipment_tracking_v2` function correctly extends the original tracking functionality by adding the notification type to the result set. This allows consumers to distinguish between notifications and reminders when tracking shipments.

The implementation properly:
1. Retrieves the type from the orders table
2. Includes it in all tracking result sets (order_tracking, email_tracking, sms_tracking)
3. Maintains compatibility with existing tracking behavior

---

`778-803`: **Properly overloaded insertorder function with type support**

The new overload of the `insertorder` function correctly:
1. Accepts the new type parameter
2. Casts it to the appropriate PostgreSQL enum type (`public.notificationordertypes`)
3. Includes it in the INSERT statement
4. Preserves the same return behavior as the other overloads

This ensures consistent type information storage in the database.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T12:46:55Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs (1)</summary><blockquote>

`121-132`: **Consider adding test for OrderTypes.Reminder**

The current tests verify serialization/deserialization for `OrderTypes.Notification`, but there's no coverage for `OrderTypes.Reminder` which is the other enum value mentioned in the PR summary. Consider adding test coverage for reminder type orders as well.


```csharp
[Fact]
public void Deserialize_Static_ReminderType()
{
    // Arrange
    var reminderOrder = new NotificationOrder
    {
        Id = Guid.NewGuid(),
        Type = OrderTypes.Reminder,
        // other properties similar to _order
    };
    
    var serializedReminderOrder = new JsonObject
    {
        // properties similar to _serializedOrder
        { "type", "Reminder" },
        // other properties
    }.ToJsonString();

    // Act
    var actual = NotificationOrder.Deserialize(serializedReminderOrder);

    // Assert
    Assert.Equivalent(reminderOrder, actual);
    Assert.Equal(OrderTypes.Reminder, actual.Type);
}
```


Also applies to: 134-145

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 10247d1729abdc4bff02306d02af1409bc9bca19 and 166d9f7c9a5a32470352ac2c26debcf0bc80e48c.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs` (2 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Analyze (csharp)
* GitHub Check: Build, test & analyze

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs (2)</summary>

`29-29`: **Addition of Type property matches PR requirements.**

The explicit assignment of `OrderTypes.Notification` to the notification order matches the PR objective of displaying notification type correctly. This ensures the test model properly represents a notification order.

---

`78-78`: **Serialized JSON now includes type field.**

The addition of the type field in the serialized JSON representation properly mirrors the model change, ensuring that serialization/deserialization tests correctly validate the new type property.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:03:56Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 166d9f7c9a5a32470352ac2c26debcf0bc80e48c and bbbbf1069e9bc73ed373348caad9d679e6b33e2a.

</details>

<details>
<summary>📒 Files selected for processing (14)</summary>

* `src/Altinn.Notifications.Core/Services/Interfaces/IOrderRequestService.cs` (3 hunks)
* `src/Altinn.Notifications.Core/Services/OrderRequestService.cs` (6 hunks)
* `src/Altinn.Notifications.Core/Shared/Result.cs` (1 hunks)
* `src/Altinn.Notifications/Controllers/FutureOrdersController.cs` (2 hunks)
* `test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs` (3 hunks)
* `test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs` (29 hunks)
* `test/Altinn.Notifications.Tests/Notifications/TestingControllers/FutureOrdersControllerTests.cs` (1 hunks)
* `test/bruno/Notifications-v2/collection.bru` (1 hunks)
* `test/bruno/Notifications-v2/create notifications/Demo notification with 2 reminders.bru` (2 hunks)
* `test/bruno/Notifications-v2/create notifications/Fulfilling eForv. §8 - custom sender.bru` (1 hunks)
* `test/bruno/Notifications-v2/create notifications/Fulfilling eForvaltningsforskriften §8.bru` (1 hunks)
* `test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru` (1 hunks)
* `test/bruno/Notifications-v2/create notifications/Validation demo - functional.bru` (1 hunks)
* `test/bruno/Notifications-v2/environments/v2 at22.bru` (1 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (2)</summary>

* test/bruno/Notifications-v2/environments/v2 at22.bru
* src/Altinn.Notifications.Core/Shared/Result.cs

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (4)</summary>

<details>
<summary>src/Altinn.Notifications/Controllers/FutureOrdersController.cs (2)</summary><blockquote>

<details>
<summary>test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs (2)</summary>

* `NotificationOrderChainResponse` (823-835)
* `NotificationOrderChainResponse` (879-910)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainResponse.cs (1)</summary>

* `NotificationOrderChainResponse` (11-28)

</details>

</blockquote></details>
<details>
<summary>src/Altinn.Notifications.Core/Services/Interfaces/IOrderRequestService.cs (4)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Shared/Result.cs (2)</summary>

* `Result` (14-19)
* `Result` (21-26)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainResponse.cs (1)</summary>

* `NotificationOrderChainResponse` (11-28)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Shared/ServiceError.cs (3)</summary>

* `ServiceError` (6-35)
* `ServiceError` (22-26)
* `ServiceError` (31-34)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs (3)</summary>

* `NotificationOrderChainRequest` (9-271)
* `NotificationOrderChainRequest` (14-16)
* `NotificationOrderChainRequest` (228-269)

</details>

</blockquote></details>
<details>
<summary>test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs (1)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (6)</summary>

* `Task` (48-79)
* `Task` (82-85)
* `Task` (88-149)
* `Task` (188-217)
* `Task` (235-284)
* `Task` (423-457)

</details>

</blockquote></details>
<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (9)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs (14)</summary>

* `Task` (48-65)
* `Task` (68-86)
* `Task` (89-112)
* `Task` (115-179)
* `Task` (182-188)
* `Task` (191-206)
* `Task` (209-229)
* `Task` (232-268)
* `Task` (271-293)
* `Task` (347-389)
* `Task` (391-409)
* `Task` (411-425)
* `Task` (427-443)
* `NotificationOrderChainResponse` (467-481)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Services/Interfaces/IOrderRequestService.cs (3)</summary>

* `Task` (17-17)
* `Task` (47-47)
* `Task` (69-69)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Shared/Result.cs (2)</summary>

* `Result` (14-19)
* `Result` (21-26)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Shared/ServiceError.cs (3)</summary>

* `ServiceError` (6-35)
* `ServiceError` (22-26)
* `ServiceError` (31-34)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs (3)</summary>

* `NotificationOrderChainRequest` (9-271)
* `NotificationOrderChainRequest` (14-16)
* `NotificationOrderChainRequest` (228-269)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs (4)</summary>

* `NotificationOrder` (11-138)
* `NotificationOrder` (59-85)
* `NotificationOrder` (90-93)
* `NotificationOrder` (106-109)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Recipient.cs (4)</summary>

* `Recipient` (10-61)
* `Recipient` (35-37)
* `Recipient` (45-50)
* `Recipient` (56-60)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Recipients/NotificationRecipient.cs (1)</summary>

* `NotificationRecipient` (6-31)

</details>
<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs (1)</summary>

* `NotificationReminder` (9-70)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Analyze (csharp)
* GitHub Check: Build, test & analyze

</details>

<details>
<summary>🔇 Additional comments (38)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (15)</summary>

`10-10`: **Add new import for Result pattern**

The inclusion of the `Altinn.Notifications.Core.Shared` namespace provides access to the `Result<TValue, TError>` pattern used to better handle errors throughout the service implementation.

---

`87-88`: **Update return type to support proper error handling**

Good improvement! The method now returns a `Result<NotificationOrderChainResponse, ServiceError>` instead of directly throwing exceptions, allowing callers to handle error cases more gracefully.

---

`94-107`: **Add explicit order type handling and improve error flow**

The code now properly includes the order type when creating notification orders and has explicit error handling. This change improves the robustness of the system by:
1. Ensuring orders have proper type classification
2. Returning early when encountering errors
3. Preserving error details for the caller

This is a good improvement that provides better clarity on error conditions.

---

`115-118`: **Add error propagation for reminder creation failures**

The addition of error checking for reminder creation ensures that failures are properly captured and returned to the caller rather than being silently ignored.

---

`120-120`: **Update to access the value from Result object**

The code now correctly accesses the `Value` property from the `Result` object, aligning with the new error handling pattern.

---

`124-124`: **Return explicit ServiceError instead of throwing exception**

Good change! The method now returns a structured `ServiceError` with HTTP status code 422 and a descriptive message instead of throwing an exception, which aligns with the new error handling approach.

---

`175-181`: **Update method documentation to include order type and Result pattern**

The documentation has been properly updated to reflect the new `orderType` parameter and the dual return type pattern (success or error).

---

`188-188`: **Update method signature for order type and Result pattern**

The method now returns a `Result<NotificationOrder, ServiceError>` and accepts an `OrderTypes orderType` parameter, correctly implementing the new typing system.

---

`192-192`: **Add resource ID sanitization**

The code now uses the new `GetSanitizedResourceId` helper method to ensure proper formatting of resource IDs before passing them to the contact point service.

---

`196-196`: **Return ServiceError for missing contact information**

Good improvement! Instead of throwing an exception, the method now returns a structured `ServiceError` with a descriptive message when recipients are missing contact information.

---

`214-215`: **Set order type on NotificationOrder**

The code now properly sets both the `SendingTimePolicy` and the new `Type` property on the `NotificationOrder`, ensuring the order type is tracked throughout the system.

---

`219-233`: **Add helper method to sanitize resource IDs**

Excellent addition! This helper method removes the `"urn:altinn:resource:"` prefix from resource IDs when present, ensuring consistent resource ID formatting before lookup.

---

`416-417`: **Update documentation for CreateNotificationOrders return type**

The documentation has been updated to reflect the new `Result` return type, clearly indicating both success and failure paths.

---

`423-423`: **Update method signature for CreateNotificationOrders**

The method now returns a `Result<List<NotificationOrder>, ServiceError>`, aligning with the new error handling pattern.

---

`436-454`: **Improve error handling in reminder order creation**

This code segment now properly:
1. Passes the order type to the `CreateNotificationOrder` method
2. Checks for both success and error conditions
3. Propagates errors back to the caller
4. Adds orders to the list only when successful

This is a significant improvement to error handling and flow control.

</details>
<details>
<summary>test/bruno/Notifications-v2/collection.bru (1)</summary>

`12-13`: **Improve variable naming consistency and add new reference ID**

The changes:
1. Rename `dialog-guid` to `dialog_guid` for consistent naming (using underscores)
2. Add a new `senders_reference_guid` variable with a generated UUID

This improves consistency in variable naming and supports unique sender references in test requests.

</details>
<details>
<summary>test/bruno/Notifications-v2/create notifications/Fulfilling eForv. §8 - custom sender.bru (1)</summary>

`10-10`: **Simplify authentication with inheritance**

Changed from explicit bearer token authentication to using `auth: inherit`, which inherits authentication from the parent collection. This simplifies test maintenance by centralizing authentication configuration.

</details>
<details>
<summary>test/bruno/Notifications-v2/create notifications/Demo notification with 2 reminders.bru (2)</summary>

`10-10`: **Simplify authentication with inheritance**

Changed from explicit bearer token authentication to using `auth: inherit`, which inherits authentication from the parent collection. This simplifies test maintenance by centralizing authentication configuration.

---

`20-20`: **Update variable name for consistency**

Changed from `{{dialog-guid}}` to `{{dialog_guid}}` to match the renamed variable in the collection script. This ensures consistent naming conventions across test files.

</details>
<details>
<summary>test/bruno/Notifications-v2/create notifications/Validation demo - functional.bru (2)</summary>

`10-10`: **Authentication standardization applied correctly.**

The change from an explicit bearer token to `auth: inherit` aligns with the pattern being applied across all test files for more consistent authentication handling.

---

`17-17`: **Variable naming convention improved.**

Good update from `{{dialog-guid}}` to `{{dialog_guid}}` to standardize on underscores instead of hyphens in variable names, making the naming convention more consistent across test files.

</details>
<details>
<summary>test/bruno/Notifications-v2/create notifications/Fulfilling eForvaltningsforskriften §8.bru (2)</summary>

`10-10`: **Authentication standardization applied correctly.**

The change from explicit bearer token to `auth: inherit` aligns with the pattern being applied across all test files for more consistent authentication handling.

---

`18-18`: **Variable naming convention improved.**

Good update from `{{dialog-guid}}` to `{{dialog_guid}}` to standardize on underscores instead of hyphens in variable names, making the naming convention more consistent across test files.

</details>
<details>
<summary>test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru (1)</summary>

`1-52`: **Well-structured test case for multi-organization notification scenario.**

This test case properly exercises the notification system's ability to handle a main notification targeting one organization and a reminder targeting a different organization, which is an important use case. The test follows the established patterns for authentication and payload structure.

</details>
<details>
<summary>src/Altinn.Notifications/Controllers/FutureOrdersController.cs (3)</summary>

`2-2`: **Required using directives added for new functionality.**

Appropriate directives added to support the new Result type and order models.



Also applies to: 4-4

---

`84-100`: **Improved error handling with Result pattern.**

The implementation now properly uses the Result pattern to handle both success and error cases from the service layer. This is a significant improvement over exception-based flow control and provides:

1. Clear separation between success and error paths
2. Structured error responses with appropriate status codes
3. Proper creation of ProblemDetails for standardized error reporting

---

`104-111`: **Enhanced cancellation handling with structured response.**

The improved error handling for operation cancellation now returns a proper ProblemDetails object with a descriptive title and message. This provides better client-side error information compared to the previous string-only response.

</details>
<details>
<summary>src/Altinn.Notifications.Core/Services/Interfaces/IOrderRequestService.cs (3)</summary>

`2-2`: **Appropriate namespace import added**

Adding the Core.Shared namespace supports the new Result pattern for error handling.

---

`29-31`: **XML documentation updated to reflect new return type**

The documentation now properly describes both success and failure cases of the method return.

---

`47-47`: **Good implementation of Result pattern for error handling**

Changing the return type from `Task<NotificationOrderChainResponse>` to `Task<Result<NotificationOrderChainResponse, ServiceError>>` improves error handling by making failure cases explicit in the method signature. This enables callers to handle errors in a more structured way without relying on exceptions.

</details>
<details>
<summary>test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs (4)</summary>

`11-11`: **Core.Shared namespace import added to support new error handling**

Adding the namespace is required to support the Result-based error handling used in the updated service implementation.

---

`602-610`: **Enhanced test assertions for operation canceled error handling**

The test now properly asserts the structure of the error response, verifying that the controller correctly converts operation canceled exceptions into ProblemDetails with appropriate status code and title.

---

`612-639`: **Good test coverage for missing recipients error case**

This new test verifies that when the service returns a ServiceError with code 422 and message "Missing recipients", the controller correctly maps it to a ProblemDetails response with matching status code and detail message.

---

`667-673`: **Improved assertions for operation cancellation during registration**

Test now properly checks that operation cancellation during order registration results in a ProblemDetails response with status 499 and "Request terminated" title.

</details>
<details>
<summary>test/Altinn.Notifications.Tests/Notifications/TestingControllers/FutureOrdersControllerTests.cs (4)</summary>

`1-46`: **Well-structured test class setup**

The test class follows good practices by:
1. Isolating the controller under test with mocked dependencies
2. Setting up a consistent testing context with a valid organization ID
3. Initializing the resource link extensions for URL generation

---

`48-88`: **Good test for successful order creation**

This test verifies that a valid request results in:
1. A call to the service layer with appropriate parameters
2. A CreatedResult response with the expected status code

---

`90-108`: **Proper validation error handling test**

This test confirms that invalid requests (missing required properties) are correctly rejected with a BadRequest response containing ValidationProblemDetails.

---

`110-147`: **Comprehensive service error handling test**

This test thoroughly verifies that when the service returns a ServiceError:
1. The controller returns an ObjectResult with the appropriate status code
2. The response contains a ProblemDetails object with the error message from the service
3. The error is properly propagated to the client

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T10:54:52Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T10:58:41Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T10:59:10Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T10:59:55Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T11:01:13Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T11:03:32Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T11:04:43Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T11:10:24Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T11:10:51Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (3)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (3)</summary><blockquote>

`50-56`: **Rename `currentime` → `currentTime` for clarity & consistency**

`currentime` is a typo and deviates from the camel-case convention used elsewhere (`currentTime` in other methods). Besides harming readability, it is easy to grep-miss later.

```diff
-        DateTime currentime = _dateTime.UtcNow();
+        DateTime currentTime = _dateTime.UtcNow();
```
Adjust the three subsequent usages as well.

---

`320-323`: **422 might not be semantically correct for internal repository failures**

`422 Unprocessable Entity` signals client input errors. A repository failure (`null`/empty list) is more likely a server-side problem (`500`) or a conflict (`409`).  
Aligning status codes with RFC semantics will help API consumers distinguish between *their* mistakes and *our* outages.

---

`351-361`: **Minor optimisation & early-exit**

`GetSanitizedResourceId` currently allocates two strings when the prefix exists (`StartsWith` + `Replace`).  
Simple early-exit reduces that to one:

```diff
-        if (!string.IsNullOrWhiteSpace(resourceId))
-        {
-            if (resourceId.StartsWith("urn:altinn:resource:"))
-            {
-                return resourceId.Replace("urn:altinn:resource:", string.Empty);
-            }
-            return resourceId;
-        }
-        return null;
+        if (string.IsNullOrWhiteSpace(resourceId))
+        {
+            return null;
+        }
+        return resourceId.StartsWith("urn:altinn:resource:", StringComparison.Ordinal)
+            ? resourceId["urn:altinn:resource:".Length..]
+            : resourceId;
```
Tiny, but avoids an extra pass over the string.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between efc241ca9238339697071da75b7a64d8fb6cb91a and 59371d49498e47d26d50ae8af661c885f4b219ab.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `src/Altinn.Notifications.Core/Services/OrderRequestService.cs` (2 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Analyze (csharp)
* GitHub Check: Build, test & analyze

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (2)</summary>

`247-248`: **Partial progress gets lost on first reminder failure**

When the loop hits the first reminder with missing contact info you:

```csharp
return new ServiceError(422, ...);
```

All successfully built `NotificationOrder`s in `reminders` are discarded.  
If that is intentional (atomic “all-or-nothing” semantics), please add an inline comment.  
If not, you might want to commit the valid reminders and only skip the failing one.

---

`553-621`: **ExtractDeliveryComponents – default channel is hard-coded to SMS**

When none of the specialised recipient types matches, the method silently defaults to `NotificationChannel.Sms` (line 561).  
If new recipient types are added later, this can lead to unintentionally sending SMS. Consider:
* Throwing an exception / returning an error for unknown variants, or
* Requiring the caller to supply the fallback channel explicitly.

A defensive `switch`/`if` with an `ArgumentException` would prevent silent misrouting.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T13:44:03Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T14:09:48Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T14:11:21Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T14:12:00Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T14:12:26Z
user: login: eskebab
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T06:50:09Z
user: login: eskebab
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T07:40:55Z
user: login: eskebab
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T07:42:13Z
user: login: eskebab
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T07:49:57Z
user: login: eskebab
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T07:56:50Z
user: login: eskebab
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T08:40:40Z
user: login: eskebab
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T08:42:55Z
user: login: eskebab
body: approved with some comments
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T08:51:06Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T04:51:57Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T04:54:13Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T04:55:00Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T04:59:31Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T05:11:04Z
user: login: Ahmed-Ghanam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T05:16:09Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs (1)</summary><blockquote>

`230-233`: **Improve the exception message for invalid order type**

The exception message "Invalid type used." is not specific enough about what values are allowed or why the validation failed.

Consider improving the exception message to be more descriptive:

```diff
-                throw new InvalidOperationException("Invalid type used.");
+                throw new InvalidOperationException($"Invalid order type: {_type}. NotificationOrderChainRequest must have Type set to OrderType.Notification.");
```

</blockquote></details>
<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (1)</summary><blockquote>

`242-248`: **Consider more descriptive error handling for missing contact information**

When contact information is missing for reminder recipients, the error message could be more helpful by including which reminder (perhaps by index or ID) has the issue.

Consider enhancing the error message to identify which specific reminder has missing contact information:

```diff
-                return new ServiceError(422, $"Missing contact information for recipient(s): {string.Join(", ", lookupResult.MissingContact)}");
+                return new ServiceError(422, $"Missing contact information for recipient(s) in reminder {notificationReminder.OrderId}: {string.Join(", ", lookupResult.MissingContact)}");
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between dfee996d9743f0acbff6c2ae9d18167e1111ca58 and 06ca585281d61131a488427512406ae15566b37e.

</details>

<details>
<summary>📒 Files selected for processing (18)</summary>

* `src/Altinn.Notifications.Core/Enums/OrderType.cs` (1 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs` (1 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs` (3 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs` (5 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs` (3 hunks)
* `src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs` (2 hunks)
* `src/Altinn.Notifications.Core/Services/OrderRequestService.cs` (4 hunks)
* `src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs` (4 hunks)
* `src/Altinn.Notifications/Controllers/FutureOrdersController.cs` (1 hunks)
* `src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs` (2 hunks)
* `test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/NotificationDeliveryManifestRepositoryTests.cs` (12 hunks)
* `test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/OrderRepositoryTests.cs` (42 hunks)
* `test/Altinn.Notifications.IntegrationTests/Notifications/OrdersController/OrdersControllerTests.cs` (2 hunks)
* `test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs` (2 hunks)
* `test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs` (24 hunks)
* `test/Altinn.Notifications.Tests/Notifications/TestingMappers/NotificationOrderChainMapperTests.cs` (27 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (2)</summary>

* src/Altinn.Notifications.Core/Enums/OrderType.cs
* src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (14)</summary>

* src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs
* src/Altinn.Notifications/Controllers/FutureOrdersController.cs
* src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql
* test/Altinn.Notifications.IntegrationTests/Notifications/OrdersController/OrdersControllerTests.cs
* test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs
* src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs
* src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs
* src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs
* test/Altinn.Notifications.Tests/Notifications/TestingMappers/NotificationOrderChainMapperTests.cs
* src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
* test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/NotificationDeliveryManifestRepositoryTests.cs
* src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs
* test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/OrderRepositoryTests.cs
* test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (3)</summary>

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:156-174
Timestamp: 2025-05-18T14:12:25.106Z
Learning: The `urn:altinn:resource:` prefix should only be removed from resourceId when making contact point lookup calls, but the full unsanitized value must be persisted in the data store. This is intentional behavior in the OrderRequestService.
```

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:96-103
Timestamp: 2025-05-18T14:11:20.141Z
Learning: The Result<TValue, TError> struct in Altinn.Notifications has an implicit conversion operator from TError to Result<TValue, TError> which allows directly returning error objects from methods that return Result types.
```

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:96-103
Timestamp: 2025-05-18T14:11:20.141Z
Learning: The Result<TValue, TError> struct in Altinn.Notifications provides an implicit conversion operator from TError to Result<TValue, TError>, which allows directly returning error objects from methods that return Result types without explicitly wrapping them.
```

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Build, test & analyze
* GitHub Check: Analyze (csharp)

</details>

<details>
<summary>🔇 Additional comments (11)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs (5)</summary>

`1-1`: **Appropriate import added for OrderType enum**

The import for `Altinn.Notifications.Core.Enums` namespace is correctly added to access the `OrderType` enum.

---

`99-105`: **Good addition of the Type property with clear documentation**

The addition of the `Type` property with comprehensive XML documentation clearly explains its purpose and usage in distinguishing between initial notifications and reminders.

---

`113-113`: **Field added to support the Type property**

The private field `_type` is correctly added to the builder class to store the order type.

---

`124-133`: **Builder method for setting the order type**

The `SetType` method follows the builder pattern consistently with other setter methods in the class.

---

`257-257`: **Type property correctly initialized in Build method**

The `Type` property is properly included in the object initialization block of the `Build` method.

</details>
<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (6)</summary>

`90-111`: **Improved structure with clear method sequencing**

The refactored `RegisterNotificationOrderChain` method now has a clear, sequential structure with numbered comments indicating the processing steps. This makes the code more maintainable and easier to understand.

---

`114-152`: **Excellent XML documentation for CreateMainNotificationOrderAsync**

The comprehensive XML documentation for this method follows best practices by clearly describing parameters, return values, exceptions, and including detailed remarks about the method's behavior.

---

`156-182`: **Correctly sets order type in the main notification order**

The method properly sets the `Type` property on the notification order to the value from the request. As indicated in the retrieved learning, the unsanitized `resourceId` is correctly persisted while the sanitized version is used for lookup.

---

`185-271`: **Well-structured reminder creation method with thorough documentation**

The `CreateReminderNotificationOrdersAsync` method is well-structured with proper cancellation support, validation, and error handling. The XML documentation is comprehensive and provides clear guidance on method behavior and return values.


I note the correct setting of the `Type` property on line 260, which ensures each reminder is properly typed.

---

`273-349`: **Well-implemented chain response creation with clear error handling**

The `CreateChainResponseAsync` method properly constructs the response with main and reminder shipment information. The error handling is appropriate with clear error messages.

---

`351-359`: **Good implementation of resource ID sanitization**

The `GetSanitizedResourceId` method correctly implements the requirement to remove the `urn:altinn:resource:` prefix when needed. This addresses the learnings about only removing the prefix for contact point lookup calls while preserving the full value in the data store.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T05:18:35Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql (1)</summary><blockquote>

`778-804`: **New `insertorder` overload adds `type` parameter—valid but could be clearer.**  
- Parameter `_type` is cast to `public.notificationordertype` and inserted correctly.  
- To avoid confusion with the SQL keyword `TYPE`, consider renaming the parameter.  

Apply this diff to rename `_type` to `_ordertype`:

```diff
@@ -778,8 +778,8 @@ CREATE OR REPLACE FUNCTION notifications.insertorder(
-    _sendingtimepolicy integer,
-    _type text)
+    _sendingtimepolicy integer,
+    _ordertype text)

@@ -797,8 +797,8 @@ BEGIN
-    VALUES (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _created, _notificationorder, _sendingtimepolicy, _type::public.notificationordertype)
+    VALUES (_alternateid, _creatorname, _sendersreference, _created, _requestedsendtime, _created, _notificationorder, _sendingtimepolicy, _ordertype::public.notificationordertype)
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 06ca585281d61131a488427512406ae15566b37e and 6c7d2dbd5834c0167c1e92c2a1c7441324928154.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql` (1 hunks)
* `src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/insertorder.sql

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Build, test & analyze
* GitHub Check: Analyze (csharp)

</details>

<details>
<summary>🔇 Additional comments (12)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql (12)</summary>

`3-64`: **Function `notifications.cancelorder` looks correct.**  
Cancel logic properly handles missing orders, checks for already cancelled or late orders, and updates status when allowed. Leveraging `getorder_includestatus_v4` for details is appropriate. No changes needed to surface the new `type` here as cancellation is type-agnostic.

---

`67-86`: **Recipient‐lookup functions are solid.**  
Both `getemailrecipients_v2` and `getsmsrecipients_v2` correctly resolve the internal order ID and return the expected columns. They do not need to reference the new `type` column.  



Also applies to: 547-566

---

`87-139`: **Status‐update functions for new entries are well-implemented.**  
- `getemails_statusnew_updatestatus` and `GETSMS_STATUSNEW_UPDATESTATUS` use a CTE to atomically switch status from `New` to `Sending` and return the payload.  
- Filter and join logic is correct, and they safely handle the absence of rows.  



Also applies to: 595-635

---

`142-173`: **Summary functions handle no-data cases gracefully.**  
- `getemailsummary_v2` and `getsmssummary_v2` return actual rows when present or a single row of nulls otherwise, matching existing patterns.  



Also applies to: 644-675

---

`174-204`: **Metrics aggregation is clean and efficient.**  
The `getmetrics` function uses conditional `SUM` and grouping correctly, with clear separation of email and SMS counts.

---

`207-283`: **Detailed status retrieval remains consistent.**  
`getorder_includestatus_v4` correctly calculates email/SMS counters and projects JSONB fields. It omits `type` intentionally, focusing on status details; this aligns with its purpose.

---

`285-346`: **Consider surfacing `type` in order‐chain tracking.**  
`get_orders_chain_tracking` returns chain IDs and reminders but does not include the new `orders.type`. If the frontend or downstream consumers require knowing whether a reminder is a `Notification` vs. `Reminder`, we should extend the `RETURNS TABLE` and JSON construction to include `od.type::TEXT`.  

Please confirm if `type` should also be returned here or if it’s out of scope for this endpoint.

---

`369-386`: **Scheduled-status update for past send times is correct.**  
`getorders_pastsendtime_updatestatus` updates eligible orders to `Processing` and returns the JSON payload, unaffected by `type`.

---

`388-452`: **Original `get_shipment_tracking` preserved for compatibility.**  
Leaving the old version intact ensures backward compatibility for callers still relying on the 4-column signature.

---

`465-535`: **New `get_shipment_tracking_v2` correctly projects the `type`.**  
- Signature updated to include `type TEXT`.  
- Each CTE (`order_tracking`, `email_tracking`, `sms_tracking`) consistently selects `od.type::TEXT`.  
- Existence check and empty‐set return match the original.  
This satisfies the PR objective of exposing the notification order type in shipment tracking.

---

`676-724`: **Insert and update procedures remain sound.**  
- `insertemailnotification`, `insertemailtext`, `insertsmsnotification`, and `updateemailstatus` correctly bind parameters and cast enums.  
- No direct reference to the new `type` column is needed in these operations.  



Also applies to: 725-734, 836-884, 885-894

---

`736-777`: **Overloaded `insertorder` functions correctly leverage defaults.**  
- The two existing overloads (without `type`) rely on the database default (`Notification`) in the new `type` column.  
- Argument ordering, `RETURNING _id`, and volatility settings are appropriate.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T13:03:08Z

Review comments:
diff_hunk: @@ -33,6 +33,9 @@ public class NotificationOrderWithStatus : IBaseNotificationOrder
     /// <inheritdoc/>>
     public string? ResourceId { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderTypes Type { get; internal set; }
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Property needs initialization in constructors**

The new `Type` property isn't initialized in either constructor. Since this property is required by the interface, it should be properly initialized to avoid potential issues with default values.


Add the property to both constructors. For example:

```diff
public NotificationOrderWithStatus(
    Guid id,
    string? sendersReference,
    DateTime requestedSendTime,
    Creator creator,
    DateTime created,
    NotificationChannel notificationChannel,
    bool? ignoreReservation,
    string? resourceId,
    Uri? conditionEndpoint,
-   ProcessingStatus processingStatus)
+   ProcessingStatus processingStatus,
+   OrderTypes type)
{
    Id = id;
    SendersReference = sendersReference;
    RequestedSendTime = requestedSendTime;
    Creator = creator;
    Created = created;
    NotificationChannel = notificationChannel;
    IgnoreReservation = ignoreReservation;
    ResourceId = resourceId;
    ConditionEndpoint = conditionEndpoint;
    ProcessingStatus = processingStatus;
+   Type = type;
}
```

Make similar changes to the internal constructor to provide a default value.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
public NotificationOrderWithStatus(
    Guid id,
    string? sendersReference,
    DateTime requestedSendTime,
    Creator creator,
    DateTime created,
    NotificationChannel notificationChannel,
    bool? ignoreReservation,
    string? resourceId,
    Uri? conditionEndpoint,
    ProcessingStatus processingStatus,
    OrderTypes type)
{
    Id = id;
    SendersReference = sendersReference;
    RequestedSendTime = requestedSendTime;
    Creator = creator;
    Created = created;
    NotificationChannel = notificationChannel;
    IgnoreReservation = ignoreReservation;
    ResourceId = resourceId;
    ConditionEndpoint = conditionEndpoint;
    ProcessingStatus = processingStatus;
    Type = type;
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs at
lines 36-37, the new Type property is not initialized in either constructor,
which can lead to default or incorrect values. Update both constructors to
include initialization of the Type property, assigning it an appropriate default
or passed-in value to ensure it is always set when an instance is created.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T12:46:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -58,4 +59,12 @@ public class NotificationReminder
     /// A unique identifier used by the sender to correlate this reminder with their internal systems.
     /// </remarks>
     public string? SendersReference { get; set; }
+
+    /// <summary>
+    /// Gets the type of the reminder.
+    /// </summary>
+    /// <remarks>
+    /// Specifies whether this is an initial notification or a reminder.
+    /// </remarks>
+    public OrderTypes Type { get; set; }
path: src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Initialize the Type property**

The `Type` property should be initialized, preferably to `OrderTypes.Reminder` since this class represents a reminder notification.


```diff
/// <summary>
/// Gets the type of the reminder.
/// </summary>
/// <remarks>
/// Specifies whether this is an initial notification or a reminder.
/// </remarks>
-public OrderTypes Type { get; set; }
+public OrderTypes Type { get; set; } = OrderTypes.Reminder;
```

Also, consider making this property have an internal setter to be consistent with other implementations if the design requires that only internal code can modify the type.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/Altinn.Notifications.Core/Models/Orders/NotificationReminder.cs around
lines 63 to 69, initialize the Type property to OrderTypes.Reminder by default
to reflect that this class represents a reminder notification. Additionally,
change the setter of the Type property to internal if the design requires
restricting modification to internal code only, ensuring consistency with other
similar implementations.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits 8341fbd to 10247d1
created_at: 2025-05-15T12:46:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,6 +40,9 @@ public class NotificationOrder : IBaseNotificationOrder
     /// <inheritdoc/>
     public SendingTimePolicy? SendingTimePolicy { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderTypes Type { get; internal set; }
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Property needs initialization in constructors**

The new `Type` property isn't initialized in any constructor. Since this property is required by the interface implementation, it should be properly initialized to avoid default value issues.


Add the property to the main constructor:

```diff
public NotificationOrder(
    Guid id,
    string? sendersReference,
    List<INotificationTemplate> templates,
    DateTime requestedSendTime,
    NotificationChannel notificationChannel,
    Creator creator,
    DateTime created,
    List<Recipient> recipients,
    bool? ignoreReservation,
    string? resourceId,
-   Uri? conditionEndpoint)
+   Uri? conditionEndpoint,
+   OrderTypes type)
{
    Id = id;
    SendersReference = sendersReference;
    Templates = templates;
    RequestedSendTime = requestedSendTime;
    NotificationChannel = notificationChannel;
    Creator = creator;
    Created = created;
    Recipients = recipients;
    IgnoreReservation = ignoreReservation;
    ResourceId = resourceId;
    ConditionEndpoint = conditionEndpoint;
+   Type = type;
}
```

Also, update the internal constructor to provide a default Type value:

```diff
internal NotificationOrder()
{
    Creator = new Creator(string.Empty);
+   Type = OrderTypes.Notification; // Default to Notification type
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
// File: src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs

public class NotificationOrder
{
    // Existing members…

    /// <inheritdoc/>
    public OrderTypes Type { get; internal set; }

    public NotificationOrder(
        Guid id,
        string? sendersReference,
        List<INotificationTemplate> templates,
        DateTime requestedSendTime,
        NotificationChannel notificationChannel,
        Creator creator,
        DateTime created,
        List<Recipient> recipients,
        bool? ignoreReservation,
        string? resourceId,
        Uri? conditionEndpoint,
        OrderTypes type)  // added
    {
        Id = id;
        SendersReference = sendersReference;
        Templates = templates;
        RequestedSendTime = requestedSendTime;
        NotificationChannel = notificationChannel;
        Creator = creator;
        Created = created;
        Recipients = recipients;
        IgnoreReservation = ignoreReservation;
        ResourceId = resourceId;
        ConditionEndpoint = conditionEndpoint;
        Type = type;  // added
    }

    internal NotificationOrder()
    {
        Creator = new Creator(string.Empty);
        Type = OrderTypes.Notification; // Default to Notification type
    }

    // Remaining members…
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs at lines
43-44, the new Type property is not initialized in any constructor, which can
lead to default value issues. Modify the main constructor to accept a Type
parameter and assign it to the Type property. Also, update the internal
constructor to set a default Type value to ensure the property is always
properly initialized.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T12:46:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+meta {
+  name: Two organizations - One reminder
+  type: http
+  seq: 5
+}
+
+post {
+  url: {{host}}/notifications/api/v1/future/orders
+  body: json
+  auth: inherit
+}
+
+body:json {
+  {
+    "sendersReference": "{{senders_reference_guid}}",
+    "idempotencyId": "{{random_idempotency_id}}",
+    "recipient": {
+      "recipientOrganization": {
+        "orgNumber": "312508729",
+        "channelSchema": "EmailAndSms",
+        "resourceId": "urn:altinn:resource:app_ttd_rf-545454545",
+        "smsSettings": {
+          "sendingTimePolicy": "Daytime",
+          "body": "Dear $recipientName$, please check your email for an important update regarding your account $recipientNumber$. - Altinn Team"
+        },
+        "emailSettings": {
+          "contentType": "Plain",
+          "sendingTimePolicy": "Anytime",
+          "subject": "Important Update Regarding Your Account",
+          "body": "Dear $recipientName$,\n\nWe wanted to inform you about an important update to your account $recipientNumber$. Please log in to your dashboard to review the changes.\n\nBest regards,\nAltinn Team"
+        }
+      }
+    },
+    "reminders": [
+      {
+        "delayDays": 1,
+        "recipient": {
+          "recipientOrganization": {
+            "emailSettings": {
+              "subject": "Important Update Regarding Your Account",
+              "body": "Dear $recipientName$,\n\nWe wanted to inform you about an important update to your account $recipientNumber$. Please log in to your dashboard to review the changes.\n\nBest regards,\nAltinn Team",
+              "contentType": "Plain",
+              "sendingTimePolicy": "Anytime"
+            },
+            "orgNumber": "974761076",
+            "channelSchema": "Email"
+          }
+        }
path: test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Consider adding resourceId to reminder recipient.**

The main notification includes a `resourceId` parameter, but the reminder recipient does not. This might be intentional, but verify if the `resourceId` should be included in the reminder as well for consistency.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if resourceId is required or optional in reminders by examining other test files
echo "Checking reminder definitions in other test files..."
rg -A 5 -B 5 '"reminders"' --glob='*.bru' | grep -A 10 "recipientOrganization" | grep -E "resourceId"
```

Length of output: 214

---

To be sure we’re not missing any `resourceId` usages in reminder definitions, let’s search across all `.bru` test files for the exact key:

---

🏁 Script executed:

```shell
#!/bin/bash
echo "Searching for resourceId in all .bru test files with context..."
rg -A3 -B3 '"resourceId"' --glob='*.bru'
```

Length of output: 7976

---



</details>

**Add `resourceId` to the reminder’s recipientOrganization for consistency**

The reminder block in  
`test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru`  
currently omits `resourceId`, whereas the main notification includes it. Please insert the same resource identifier used above.

• File: `test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru`  
  Location: within the reminder’s  
  `"recipientOrganization"` block (around lines 36–48)  
  Suggested insertion:
  ```diff
           "recipientOrganization": {
  +          "resourceId": "urn:altinn:resource:app_ttd_rf-545454545",
            "orgNumber": "974761076",
            "channelSchema": "Email",
            "emailSettings": {
              …  
  ```  


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
        "delayDays": 1,
        "recipient": {
          "recipientOrganization": {
            "emailSettings": {
              "subject": "Important Update Regarding Your Account",
              "body": "Dear $recipientName$,\n\nWe wanted to inform you about an important update to your account $recipientNumber$. Please log in to your dashboard to review the changes.\n\nBest regards,\nAltinn Team",
              "contentType": "Plain",
              "sendingTimePolicy": "Anytime"
            },
            "resourceId": "urn:altinn:resource:app_ttd_rf-545454545",
            "orgNumber": "974761076",
            "channelSchema": "Email"
          }
        }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In test/bruno/Notifications-v2/create notifications/Two organizations - One
reminder.bru around lines 36 to 48, the reminder's recipientOrganization block
is missing the resourceId field that is present in the main notification. To fix
this, add the same resourceId value used in the main notification into the
recipientOrganization block of the reminder to maintain consistency across the
notification definitions.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T10:54:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,13 +80,35 @@ public async Task<ActionResult<NotificationOrderChainResponseExt>> Post(Notifica
             }
 
             var notificationOrderChainRequest = notificationOrderRequest.MapToNotificationOrderChainRequest(creator);
-            var registeredNotificationOrderChain = await _orderRequestService.RegisterNotificationOrderChain(notificationOrderChainRequest, cancellationToken);
 
-            return Created(registeredNotificationOrderChain.OrderChainId.GetSelfLinkFromOrderChainId(), registeredNotificationOrderChain.MapToNotificationOrderChainResponseExt());
+            Result<NotificationOrderChainResponse, ServiceError> result = await _orderRequestService.RegisterNotificationOrderChain(notificationOrderChainRequest, cancellationToken);
+
+            return result.Match(
+                registeredNotificationOrderChain =>
+                {
+                    return Created(registeredNotificationOrderChain.OrderChainId.GetSelfLinkFromOrderChainId(), registeredNotificationOrderChain.MapToNotificationOrderChainResponseExt());
+                },
+                error =>
+                {
+                    var problemDetails = new ProblemDetails
+                    {
+                        Title = "Notification order chain registration failed",
+                        Detail = error.ErrorMessage,
+                        Status = error.ErrorCode
+                    };
+                    return StatusCode(error.ErrorCode, problemDetails);
+                });
         }
         catch (OperationCanceledException)
         {
-            return StatusCode(499, "Request terminated - The client disconnected or cancelled the request before the server could complete processing");
+            var problemDetails = new ProblemDetails
+            {
+                Title = "Request terminated",
+                Detail = "The client disconnected or cancelled the request before the server could complete processing.",
+                Status = 499
+            };
+
+            return StatusCode(499, problemDetails);
path: src/Altinn.Notifications/Controllers/FutureOrdersController.cs
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Verify consistent error handling across controller methods.**

The improvements in error handling are excellent, but it's important to ensure that other controller methods in the codebase follow this same pattern for consistency.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if other controllers use similar error handling patterns
echo "Checking for other controller methods that might need similar error handling updates:"
# Look for controllers with similar method patterns
rg -A 5 "public async Task<ActionResult<.*Response.*>> \w+" --glob='*Controller.cs' | grep -v "FutureOrdersController" | grep -A 3 "public async"

# Look for similar service method calls that likely return Result types
rg "await .*Service\.\w+" --glob='*Controller.cs' | grep -v "RegisterNotificationOrderChain" | grep "await"
```

Length of output: 4922

---



</details>

**Apply the same Result-based error handling pattern across all controllers**

We’ve improved `FutureOrdersController` to use  
```csharp
result.Match(
  onSuccess => Created(...),
  error =>
  {
    var pd = new ProblemDetails { Title = “…failed”, Detail = error.ErrorMessage, Status = error.ErrorCode };
    return StatusCode(error.ErrorCode, pd);
  });
```  
and catch `OperationCanceledException` returning a 499. To keep consistency, please update the following endpoints (all of which call services returning `Result<T, ServiceError>`) to the same pattern:

- **src/Altinn.Notifications/Controllers/ShipmentController.cs**  
  – `GetDeliveryManifestAsync(id, creatorName, cancellationToken)`  
- **src/Altinn.Notifications/Controllers/EmailNotificationsController.cs**  
  – `GetSummary(id, expectedCreator)`  
- **src/Altinn.Notifications/Controllers/SmsNotificationsController.cs**  
  – `GetSummary(id, expectedCreator)`  
- **src/Altinn.Notifications/Controllers/OrdersController.cs**  
  – `GetOrderById(id, expectedCreator)`  
  – `GetOrdersBySendersReference(sendersReference, expectedCreator)`  
  – `GetOrderWithStatusById(id, expectedCreator)`  
  – `CancelOrder(id, expectedCreator)`  

For each, wrap the service call in a `try { … } catch (OperationCanceledException)` block (returning a 499 with `ProblemDetails`), then use `result.Match(…)` to return success or map `ServiceError` to `ProblemDetails` with the appropriate status code.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/Altinn.Notifications/Controllers/ShipmentController.cs,
EmailNotificationsController.cs, SmsNotificationsController.cs, and
OrdersController.cs, update the specified async methods to use the same
Result-based error handling pattern as in FutureOrdersController.cs lines
84-111. Wrap the service call returning Result<T, ServiceError> in a try-catch
block catching OperationCanceledException and returning a 499 status with
ProblemDetails. Then use result.Match to return Created or appropriate success
responses on success, and map ServiceError to ProblemDetails with the error
message and status code on failure. This ensures consistent error handling and
response formatting across all controllers.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T10:54:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,6 +33,9 @@ public class NotificationOrderWithStatus : IBaseNotificationOrder
     /// <inheritdoc/>>
     public string? ResourceId { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderTypes Type { get; internal set; }
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs
user: login: Ahmed-Ghanam
body: This is addressed. Can you double check?
created_at: 2025-05-18T10:58:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,6 +33,9 @@ public class NotificationOrderWithStatus : IBaseNotificationOrder
     /// <inheritdoc/>>
     public string? ResourceId { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderTypes Type { get; internal set; }
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrderWithStatus.cs
user: login: coderabbitai[bot]
body: @Ahmed-Ghanam I've verified that the issue has been properly addressed. The `Type` property is now correctly initialized in the main constructor with the `OrderTypes type` parameter. The internal constructor doesn't initialize this property, but that's acceptable since it's an internal constructor likely used for serialization/deserialization purposes. Thank you for making the fix!

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20caught%20a%20critical%20miss%3A%20always%20initialize%20new%20properties%20like%20%60Type%60%20in%20all%20constructors%20to%20prevent%20default%20value%20bugs!%20%F0%9F%9B%A0%EF%B8%8F%20Boost%20your%20code%20reliability%E2%80%94try%20%40coderabbitai%20today!%20%F0%9F%9A%80&url=https%3A%2F%2Fgithub.com%2FAltinn%2Faltinn-notifications%2Fpull%2F851%23discussion_r2091093993)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@Ahmed-Ghanam I've verified that the issue has been properly addressed. The `Type` property is now correctly initialized in the main constructor with the `OrderTypes type` parameter. The internal constructor doesn't initialize this property, but that's acceptable since it's an internal constructor likely used for serialization/deserialization purposes. Thank you for making the fix!

---

&lt;!-- This is an auto-generated comment: tweet message by coderabbit.ai --&gt;

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20caught%20a%20critical%20miss%3A%20always%20initialize%20new%20properties%20like%20%60Type%60%20in%20all%20constructors%20to%20prevent%20default%20value%20bugs!%20%F0%9F%9B%A0%EF%B8%8F%20Boost%20your%20code%20reliability%E2%80%94try%20%40coderabbitai%20today!%20%F0%9F%9A%80&url=https%3A%2F%2Fgithub.com%2FAltinn%2Faltinn-notifications%2Fpull%2F851%23discussion_r2091093993)?

Thank you for using CodeRabbit!

&lt;!-- end of auto-generated comment: tweet message by coderabbit.ai --&gt;

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T10:59:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,6 +40,9 @@ public class NotificationOrder : IBaseNotificationOrder
     /// <inheritdoc/>
     public SendingTimePolicy? SendingTimePolicy { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderTypes Type { get; internal set; }
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
user: login: Ahmed-Ghanam
body: This is addressed. Can you double check?
We do not need to have a default value in the internal constructor.
created_at: 2025-05-18T10:59:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,6 +40,9 @@ public class NotificationOrder : IBaseNotificationOrder
     /// <inheritdoc/>
     public SendingTimePolicy? SendingTimePolicy { get; internal set; }
 
+    /// <inheritdoc/>
+    public OrderTypes Type { get; internal set; }
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
user: login: coderabbitai[bot]
body: @Ahmed-Ghanam I've verified the fix and it looks good! The main constructor now correctly accepts the `OrderTypes type` parameter and initializes the `Type` property with it.

Regarding the internal constructor, I understand your decision not to add a default value there. Since you've explicitly stated this is intentional and the property has an internal setter, I assume you're handling the initialization of this property appropriately whenever this constructor is used.

The issue is resolved. Thanks for making the fix!

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=Never%20leave%20required%20properties%20uninitialized!%20%40coderabbitai%20caught%20a%20missing%20constructor%20init%20for%20a%20critical%20Type%20property%2C%20preventing%20default%20value%20bugs.%20Boost%20your%20code%20safety%20today!%20%F0%9F%94%A7%E2%9C%A8&url=https%3A%2F%2Fgithub.com%2FAltinn%2Faltinn-notifications%2Fpull%2F851%23discussion_r2091094000)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@Ahmed-Ghanam I've verified the fix and it looks good! The main constructor now correctly accepts the `OrderTypes type` parameter and initializes the `Type` property with it.

Regarding the internal constructor, I understand your decision not to add a default value there. Since you've explicitly stated this is intentional and the property has an internal setter, I assume you're handling the initialization of this property appropriately whenever this constructor is used.

The issue is resolved. Thanks for making the fix!

---

&lt;!-- This is an auto-generated comment: tweet message by coderabbit.ai --&gt;

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=Never%20leave%20required%20properties%20uninitialized!%20%40coderabbitai%20caught%20a%20missing%20constructor%20init%20for%20a%20critical%20Type%20property%2C%20preventing%20default%20value%20bugs.%20Boost%20your%20code%20safety%20today!%20%F0%9F%94%A7%E2%9C%A8&url=https%3A%2F%2Fgithub.com%2FAltinn%2Faltinn-notifications%2Fpull%2F851%23discussion_r2091094000)?

Thank you for using CodeRabbit!

&lt;!-- end of auto-generated comment: tweet message by coderabbit.ai --&gt;

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T11:01:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+meta {
+  name: Two organizations - One reminder
+  type: http
+  seq: 5
+}
+
+post {
+  url: {{host}}/notifications/api/v1/future/orders
+  body: json
+  auth: inherit
+}
+
+body:json {
+  {
+    "sendersReference": "{{senders_reference_guid}}",
+    "idempotencyId": "{{random_idempotency_id}}",
+    "recipient": {
+      "recipientOrganization": {
+        "orgNumber": "312508729",
+        "channelSchema": "EmailAndSms",
+        "resourceId": "urn:altinn:resource:app_ttd_rf-545454545",
+        "smsSettings": {
+          "sendingTimePolicy": "Daytime",
+          "body": "Dear $recipientName$, please check your email for an important update regarding your account $recipientNumber$. - Altinn Team"
+        },
+        "emailSettings": {
+          "contentType": "Plain",
+          "sendingTimePolicy": "Anytime",
+          "subject": "Important Update Regarding Your Account",
+          "body": "Dear $recipientName$,\n\nWe wanted to inform you about an important update to your account $recipientNumber$. Please log in to your dashboard to review the changes.\n\nBest regards,\nAltinn Team"
+        }
+      }
+    },
+    "reminders": [
+      {
+        "delayDays": 1,
+        "recipient": {
+          "recipientOrganization": {
+            "emailSettings": {
+              "subject": "Important Update Regarding Your Account",
+              "body": "Dear $recipientName$,\n\nWe wanted to inform you about an important update to your account $recipientNumber$. Please log in to your dashboard to review the changes.\n\nBest regards,\nAltinn Team",
+              "contentType": "Plain",
+              "sendingTimePolicy": "Anytime"
+            },
+            "orgNumber": "974761076",
+            "channelSchema": "Email"
+          }
+        }
path: test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru
user: login: Ahmed-Ghanam
body: The users can have resource identifier in the main notification and omit it in the reminder. This is a acceptable request.
created_at: 2025-05-18T11:03:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+meta {
+  name: Two organizations - One reminder
+  type: http
+  seq: 5
+}
+
+post {
+  url: {{host}}/notifications/api/v1/future/orders
+  body: json
+  auth: inherit
+}
+
+body:json {
+  {
+    "sendersReference": "{{senders_reference_guid}}",
+    "idempotencyId": "{{random_idempotency_id}}",
+    "recipient": {
+      "recipientOrganization": {
+        "orgNumber": "312508729",
+        "channelSchema": "EmailAndSms",
+        "resourceId": "urn:altinn:resource:app_ttd_rf-545454545",
+        "smsSettings": {
+          "sendingTimePolicy": "Daytime",
+          "body": "Dear $recipientName$, please check your email for an important update regarding your account $recipientNumber$. - Altinn Team"
+        },
+        "emailSettings": {
+          "contentType": "Plain",
+          "sendingTimePolicy": "Anytime",
+          "subject": "Important Update Regarding Your Account",
+          "body": "Dear $recipientName$,\n\nWe wanted to inform you about an important update to your account $recipientNumber$. Please log in to your dashboard to review the changes.\n\nBest regards,\nAltinn Team"
+        }
+      }
+    },
+    "reminders": [
+      {
+        "delayDays": 1,
+        "recipient": {
+          "recipientOrganization": {
+            "emailSettings": {
+              "subject": "Important Update Regarding Your Account",
+              "body": "Dear $recipientName$,\n\nWe wanted to inform you about an important update to your account $recipientNumber$. Please log in to your dashboard to review the changes.\n\nBest regards,\nAltinn Team",
+              "contentType": "Plain",
+              "sendingTimePolicy": "Anytime"
+            },
+            "orgNumber": "974761076",
+            "channelSchema": "Email"
+          }
+        }
path: test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru
user: login: coderabbitai[bot]
body: @Ahmed-Ghanam Thank you for the clarification. I understand now that having a resourceId in the main notification while omitting it in the reminder is an acceptable configuration. I'll keep this in mind for future reviews.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru:36-48
Timestamp: 2025-05-18T11:04:29.570Z
Learning: In the Altinn Notifications system, it's acceptable for a main notification to have a resourceId while its reminders omit it. The resourceId field is optional in reminder objects, and notifications and reminders can have different configurations.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@Ahmed-Ghanam Thank you for the clarification. I understand now that having a resourceId in the main notification while omitting it in the reminder is an acceptable configuration. I'll keep this in mind for future reviews.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: test/bruno/Notifications-v2/create notifications/Two organizations - One reminder.bru:36-48
Timestamp: 2025-05-18T11:04:29.570Z
Learning: In the Altinn Notifications system, it's acceptable for a main notification to have a resourceId while its reminders omit it. The resourceId field is optional in reminder objects, and notifications and reminders can have different configurations.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T11:04:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,13 +80,35 @@ public async Task<ActionResult<NotificationOrderChainResponseExt>> Post(Notifica
             }
 
             var notificationOrderChainRequest = notificationOrderRequest.MapToNotificationOrderChainRequest(creator);
-            var registeredNotificationOrderChain = await _orderRequestService.RegisterNotificationOrderChain(notificationOrderChainRequest, cancellationToken);
 
-            return Created(registeredNotificationOrderChain.OrderChainId.GetSelfLinkFromOrderChainId(), registeredNotificationOrderChain.MapToNotificationOrderChainResponseExt());
+            Result<NotificationOrderChainResponse, ServiceError> result = await _orderRequestService.RegisterNotificationOrderChain(notificationOrderChainRequest, cancellationToken);
+
+            return result.Match(
+                registeredNotificationOrderChain =>
+                {
+                    return Created(registeredNotificationOrderChain.OrderChainId.GetSelfLinkFromOrderChainId(), registeredNotificationOrderChain.MapToNotificationOrderChainResponseExt());
+                },
+                error =>
+                {
+                    var problemDetails = new ProblemDetails
+                    {
+                        Title = "Notification order chain registration failed",
+                        Detail = error.ErrorMessage,
+                        Status = error.ErrorCode
+                    };
+                    return StatusCode(error.ErrorCode, problemDetails);
+                });
         }
         catch (OperationCanceledException)
         {
-            return StatusCode(499, "Request terminated - The client disconnected or cancelled the request before the server could complete processing");
+            var problemDetails = new ProblemDetails
+            {
+                Title = "Request terminated",
+                Detail = "The client disconnected or cancelled the request before the server could complete processing.",
+                Status = 499
+            };
+
+            return StatusCode(499, problemDetails);
path: src/Altinn.Notifications/Controllers/FutureOrdersController.cs
user: login: Ahmed-Ghanam
body: I'll apply the same pattern for the `GetDeliveryManifestAsync(id, creatorName, cancellationToken)` endpoint just because it's not very important for other endpoints at this time.
created_at: 2025-05-18T11:10:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,13 +80,35 @@ public async Task<ActionResult<NotificationOrderChainResponseExt>> Post(Notifica
             }
 
             var notificationOrderChainRequest = notificationOrderRequest.MapToNotificationOrderChainRequest(creator);
-            var registeredNotificationOrderChain = await _orderRequestService.RegisterNotificationOrderChain(notificationOrderChainRequest, cancellationToken);
 
-            return Created(registeredNotificationOrderChain.OrderChainId.GetSelfLinkFromOrderChainId(), registeredNotificationOrderChain.MapToNotificationOrderChainResponseExt());
+            Result<NotificationOrderChainResponse, ServiceError> result = await _orderRequestService.RegisterNotificationOrderChain(notificationOrderChainRequest, cancellationToken);
+
+            return result.Match(
+                registeredNotificationOrderChain =>
+                {
+                    return Created(registeredNotificationOrderChain.OrderChainId.GetSelfLinkFromOrderChainId(), registeredNotificationOrderChain.MapToNotificationOrderChainResponseExt());
+                },
+                error =>
+                {
+                    var problemDetails = new ProblemDetails
+                    {
+                        Title = "Notification order chain registration failed",
+                        Detail = error.ErrorMessage,
+                        Status = error.ErrorCode
+                    };
+                    return StatusCode(error.ErrorCode, problemDetails);
+                });
         }
         catch (OperationCanceledException)
         {
-            return StatusCode(499, "Request terminated - The client disconnected or cancelled the request before the server could complete processing");
+            var problemDetails = new ProblemDetails
+            {
+                Title = "Request terminated",
+                Detail = "The client disconnected or cancelled the request before the server could complete processing.",
+                Status = 499
+            };
+
+            return StatusCode(499, problemDetails);
path: src/Altinn.Notifications/Controllers/FutureOrdersController.cs
user: login: coderabbitai[bot]
body: @Ahmed-Ghanam Sounds good! Implementing the Result-based error handling pattern for the `GetDeliveryManifestAsync` endpoint is a great start. Taking an incremental approach makes sense, and you can always extend the pattern to other endpoints when it becomes more important for your project. Thanks for considering the suggestion!


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@Ahmed-Ghanam Sounds good! Implementing the Result-based error handling pattern for the `GetDeliveryManifestAsync` endpoint is a great start. Taking an incremental approach makes sense, and you can always extend the pattern to other endpoints when it becomes more important for your project. Thanks for considering the suggestion!</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T11:10:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,119 +85,283 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     }
 
     /// <inheritdoc/>
-    public async Task<NotificationOrderChainResponse> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
+    public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        var mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
+        {
+            return mainResult.Error;
+        }
 
-        var reminderOrders = await CreateNotificationOrders(
-            orderRequest.Reminders,
-            orderRequest.Creator,
-            currentTime,
-            cancellationToken);
+        // 4. Create reminders
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Result-vs-Error: returned type may not compile**

`RegisterNotificationOrderChain` must return  
`Result<NotificationOrderChainResponse, ServiceError>` but inside the error branches you return the bare `ServiceError`:

```csharp
return mainResult.Error;
```

Unless `Result` provides an implicit conversion from `ServiceError` **and** the project has `using static` helpers in scope, this is a compile-time mismatch.

```diff
-            return mainResult.Error;
+            return mainResult.Error; // ❓ Requires implicit operator. If none, wrap explicitly:
+            // return Result<NotificationOrderChainResponse, ServiceError>.FromError(mainResult.Error);
```

Please verify the `Result` implementation; otherwise wrap the error explicitly to avoid build breaks.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/Altinn.Notifications.Core/Services/OrderRequestService.cs around lines 96
to 103, the method RegisterNotificationOrderChain returns a Result type but
currently returns a bare ServiceError in error cases, causing a compile-time
mismatch. To fix this, wrap the ServiceError inside a Result error variant
explicitly before returning, ensuring the return type matches
Result<NotificationOrderChainResponse, ServiceError>. Verify the Result
implementation and use the appropriate constructor or factory method to create
an error Result instead of returning the error directly.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T13:44:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,119 +85,283 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     }
 
     /// <inheritdoc/>
-    public async Task<NotificationOrderChainResponse> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
+    public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        var mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
+        {
+            return mainResult.Error;
+        }
 
-        var reminderOrders = await CreateNotificationOrders(
-            orderRequest.Reminders,
-            orderRequest.Creator,
-            currentTime,
-            cancellationToken);
+        // 4. Create reminders
+        var remindersResult = await CreateReminderNotificationOrdersAsync(orderRequest.Reminders, orderRequest.Creator, currentTime, cancellationToken);
+        if (remindersResult.IsError && remindersResult.Error != null)
+        {
+            return remindersResult.Error;
+        }
 
-        List<NotificationOrder> savedOrders = await _repository.Create(orderRequest, mainOrder, reminderOrders, cancellationToken);
+        // 5. Create the response
+        return await CreateChainResponseAsync(orderRequest, mainResult.Value, remindersResult.Value, cancellationToken);
+    }
 
-        if (savedOrders == null || savedOrders.Count == 0)
+    /// <summary>
+    /// Creates the primary <see cref="NotificationOrder"/> for a notification chain by processing
+    /// recipient information, validating contact details, and configuring message templates.
+    /// </summary>
+    /// <param name="orderRequest">
+    /// The incoming chain request containing recipient information, templates, and other notification parameters.
+    /// </param>
+    /// <param name="currentTime">
+    /// The UTC timestamp to set as the creation time of the notification order.
+    /// </param>
+    /// <param name="cancellationToken">
+    /// A token that can be used to request cancellation of the asynchronous operation.
+    /// </param>
+    /// <returns>
+    /// A <see cref="Result{TValue,TError}"/> containing either:
+    /// <list type="bullet">
+    /// <item>
+    /// <description>A successful result with <see cref="Result{TValue,TError}.Value"/> containing the fully configured
+    /// <see cref="NotificationOrder"/> ready for persistence and processing</description>
+    /// </item>
+    /// <item>
+    /// <description>A failed result with <see cref="Result{TValue,TError}.Error"/> containing a
+    /// <see cref="ServiceError"/> with status code and detailed error message about the failure reason</description>
+    /// </item>
+    /// </list>
+    /// </returns>
+    /// <remarks>
+    /// This method performs recipient validation, template preparation, and order creation:
+    /// <list type="number">
+    /// <item><description>Extracts delivery components from the recipient configuration</description></item>
+    /// <item><description>Validates recipient contact information through lookup services</description></item>
+    /// <item><description>Applies default sender information where needed</description></item>
+    /// <item><description>Constructs a complete notification order with all required properties</description></item>
+    /// </list>
+    /// </remarks>
+    /// <exception cref="OperationCanceledException">
+    /// Thrown when the operation is canceled through the provided <paramref name="cancellationToken"/>.
+    /// </exception>
+    private async Task<Result<NotificationOrder, ServiceError>> CreateMainNotificationOrderAsync(NotificationOrderChainRequest orderRequest, DateTime currentTime, CancellationToken cancellationToken)
+    {
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var (recipients, templates, channel, ignoreReservation, resourceId, sendingTimePolicyForSms) = ExtractDeliveryComponents(orderRequest.Recipient);
+
+        var lookupResult = await GetRecipientLookupResult(recipients, channel, GetSanitizedResourceId(resourceId));
+
+        if (lookupResult?.MissingContact?.Count > 0)
         {
-            throw new InvalidOperationException("Failed to create the notification order chain.");
+            return new ServiceError(422, $"Missing contact information for recipient(s): {string.Join(", ", lookupResult.MissingContact)}");
         }
 
-        // Get the main order (first in the list)
-        var savedMainOrder = savedOrders[0];
+        templates = SetSenderIfNotDefined(templates);
 
-        // Create and return the response
-        return new NotificationOrderChainResponse
+        return new NotificationOrder
         {
-            OrderChainId = orderRequest.OrderChainId,
-            OrderChainReceipt = new NotificationOrderChainReceipt
-            {
-                ShipmentId = savedMainOrder.Id,
-                SendersReference = savedMainOrder.SendersReference,
-                Reminders = savedOrders.Count > 1
-                    ? [.. savedOrders
-                        .Where(e => e.Id != savedMainOrder.Id)
-                        .Select(order => new NotificationOrderChainShipment
-                        {
-                            ShipmentId = order.Id,
-                            SendersReference = order.SendersReference
-                        })]
-                    : null
-            }
+            Created = currentTime,
+            Templates = templates,
+            ResourceId = resourceId,
+            Recipients = recipients,
+            Type = orderRequest.Type,
+            Id = orderRequest.OrderId,
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Sanitised resourceId is used for lookup, but the UNSANITISED value is persisted**

`GetSanitizedResourceId` strips the `urn:altinn:resource:` prefix only for the lookup call, yet the order that is persisted still stores the original `resourceId`.

This creates divergent identifiers between:
1. Audit/tracking data (unsanitised)  
2. Contact-point lookup (sanitised)

Down-stream comparisons (`JOIN` in SQL, authorization checks, etc.) will silently fail.

Consider persisting the sanitised value instead:

```diff
-            ResourceId = resourceId,
+            ResourceId = GetSanitizedResourceId(resourceId),
```
and apply the same fix in `CreateReminderNotificationOrdersAsync`.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/Altinn.Notifications.Core/Services/OrderRequestService.cs around lines
156 to 174, the code uses a sanitized resourceId for the recipient lookup but
persists the original unsanitized resourceId in the NotificationOrder, causing
inconsistencies in downstream processes. To fix this, replace the persisted
resourceId with the sanitized version obtained from GetSanitizedResourceId
before assigning it to the NotificationOrder. Also, apply the same change in the
CreateReminderNotificationOrdersAsync method to ensure consistency across the
codebase.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T13:44:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,119 +85,283 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     }
 
     /// <inheritdoc/>
-    public async Task<NotificationOrderChainResponse> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
+    public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        var mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
+        {
+            return mainResult.Error;
+        }
 
-        var reminderOrders = await CreateNotificationOrders(
-            orderRequest.Reminders,
-            orderRequest.Creator,
-            currentTime,
-            cancellationToken);
+        // 4. Create reminders
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: Ahmed-Ghanam
body: The Result<TValue, TError> struct has an implicit conversion operator from TError that isn't visible in the snippet
created_at: 2025-05-18T14:09:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,119 +85,283 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     }
 
     /// <inheritdoc/>
-    public async Task<NotificationOrderChainResponse> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
+    public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        var mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
+        {
+            return mainResult.Error;
+        }
 
-        var reminderOrders = await CreateNotificationOrders(
-            orderRequest.Reminders,
-            orderRequest.Creator,
-            currentTime,
-            cancellationToken);
+        // 4. Create reminders
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

The file `src/Altinn.Notifications.Core/Shared/Result.cs` contains:

```csharp
namespace Altinn.Notifications.Core.Shared;

/// <summary>
/// A result which can be either a success with a value or an error with an error object.
/// </summary>
/// <typeparam name="TValue">The type of the value in case of success.</typeparam>
/// <typeparam name="TError">The type of the error in case of an error.</typeparam>
/// <remarks>Created based on <see href="https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/CSharpFunctionalExtensions/Result/Result.cs" />.</remarks>
public readonly struct Result<TValue, TError>
{
    private readonly TValue? _value;
    private readonly TError? _error;
    private readonly bool _isSuccess;

    /// <summary>
    /// Gets a value indicating whether this result is an error.
    /// </summary>
    public bool IsError => !_isSuccess;

    /// <summary>
    /// Gets a value indicating whether this result is a success.
    /// </summary>
    public bool IsSuccess => _isSuccess;

    /// <summary>
    /// Gets the error value if this result is an error, or null if it's a success.
    /// </summary>
    public TError? Error => _error;

    /// <summary>
    /// Gets the success value if this result is a success, or null if it's an error.
    /// </summary>
    public TValue? Value => _value;

    private Result(bool isSuccess, TValue? value, TError? error)
    {
        _isSuccess = isSuccess;
        _value = value;
        _error = error;
    }

    /// <summary>
    /// Performs pattern matching on the result.
    /// </summary>
    /// <typeparam name="T">The return type of the pattern matching.</typeparam>
    /// <param name="onSuccess">Function to call when the result is a success.</param>
    /// <param name="onError">Function to call when the result is an error.</param>
    /// <returns>The result of the corresponding function.</returns>
    public T Match<T>(Func<TValue, T> onSuccess, Func<TError, T> onError)
    {
        return _isSuccess ? onSuccess(_value!) : onError(_error!);
    }

    /// <summary>
    /// Creates a success result with the given value.
    /// </summary>
    /// <param name="value">The value to wrap in a success result.</param>
    /// <returns>A new success result wrapping the value.</returns>
    public static implicit operator Result<TValue, TError>(TValue value)
    {
        return new Result<TValue, TError>(true, value, default);
    }

    /// <summary>
    /// Creates an error result with the given error.
    /// </summary>
    /// <param name="error">The error to wrap in an error result.</param>
    /// <returns>A new error result wrapping the error.</returns>
    public static implicit operator Result<TValue, TError>(TError error)
    {
        return new Result<TValue, TError>(false, default, error);
    }
}
```



@Ahmed-Ghanam You're absolutely right. I've verified the code in `Result.cs` and found the implicit conversion operator you mentioned:

```csharp
public static implicit operator Result<TValue, TError>(TError error)
{
    return new Result<TValue, TError>(false, default, error);
}
```

This operator allows `ServiceError` values to be implicitly converted to `Result<NotificationOrderChainResponse, ServiceError>` with `IsSuccess = false`, making the current implementation perfectly valid. Thank you for the clarification!



---

🏁 Script executed:
```
#!/bin/bash
# Find the Result.cs file
cat src/Altinn.Notifications.Core/Shared/Result.cs
```

Length of output: 2585

---



</details>

@Ahmed-Ghanam You're absolutely right. I've examined the `Result.cs` file and confirmed there is indeed an implicit conversion operator defined:

```csharp
/// <summary>
/// Implicit operator used when creating an instance of Result when assigning an error value.
/// </summary>
/// <param name="error">An object of the type indicating failure.</param>
public static implicit operator Result<TValue, TError>(TError error) => new(error);
```

This operator allows a `ServiceError` to be implicitly converted to a `Result<NotificationOrderChainResponse, ServiceError>` with `IsError = true`, making the current implementation perfectly valid. The code is using this pattern throughout the codebase for clean error handling.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets from `src/Altinn.Notifications.Core/Shared/Result.cs` (lines 14-26)
```csharp
private Result(TValue value)
{
    IsError = false;
    _value = value;
    _error = default;
}

private Result(TError error)
{
    IsError = true;
    _value = default;
    _error = error;
}
```
- These constructors initialize a `Result<TValue, TError>` instance either with a value (success) or an error (failure).
- The constructor taking `TError` sets `IsError` to true and stores the error.
- The implicit conversion operator from `TError` to `Result<TValue, TError>` is likely implemented here or nearby (not shown in snippet), enabling returning an error directly where a `Result` is expected.

---

### Relevant snippets from `src/Altinn.Notifications.Core/Services/OrderRequestService.cs` (lines 70-130 approx)
- The method `RegisterNotificationOrderChain` returns `Task<Result<NotificationOrderChainResponse, ServiceError>>`.
- It calls `CreateMainNotificationOrderAsync` and `CreateReminderNotificationOrdersAsync`, both returning `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.
- When these methods return an error, the code returns `mainResult.Error` or `remindersResult.Error` directly, relying on implicit conversion from `ServiceError` to `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.
- This implicit conversion operator from `TError` to `Result<TValue, TError>` is not visible in the snippet but is used here.

---

### Relevant snippets from `src/Altinn.Notifications.Core/Shared/ServiceError.cs` (lines 6-35)
```csharp
public class ServiceError
{
    public int ErrorCode { get; private set; }
    public string? ErrorMessage { get; private set; }

    public ServiceError(int errorCode, string errorMessage)
    {
        ErrorCode = errorCode;
        ErrorMessage = errorMessage;
    }

    public ServiceError(int errorCode)
    {
        ErrorCode = errorCode;
    }
}
```
- `ServiceError` is the error type used as `TError` in `Result<TValue, TError>`.
- It encapsulates an error code (HTTP status code) and an optional error message.

---

### Summary of `Result<TValue, TError>` implicit conversion operator context
- The `Result<TValue, TError>` struct has constructors for success and error states.
- It likely defines an implicit conversion operator from `TError` to `Result<TValue, TError>`, allowing returning an error instance directly where a `Result` is expected.
- This operator is used in `OrderRequestService` methods like `RegisterNotificationOrderChain` to return errors from service methods without explicitly wrapping them.
- The `ServiceError` class is the error type used in these results, representing service-level errors with HTTP status codes and messages.

---

### Additional context from `OrderRequestService.cs`
- Methods like `CreateMainNotificationOrderAsync` and `CreateReminderNotificationOrdersAsync` return `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.
- When validation fails (e.g., missing contact info), they return `new ServiceError(...)`.
- The caller methods return these errors directly, relying on the implicit conversion operator to convert `ServiceError` to `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.

---

### Summary for human reviewer
- The implicit conversion operator from `TError` to `Result<TValue, TError>` is defined in the `Result` struct (not shown in snippet).
- It enables returning an error instance (like `ServiceError`) directly as a `Result` without explicit wrapping.
- This pattern is used in `OrderRequestService` to simplify error propagation in async methods returning `Result`.
- The `ServiceError` class represents the error payload in these results.

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:96-103
Timestamp: 2025-05-18T14:11:20.141Z
Learning: The Result<TValue, TError> struct in Altinn.Notifications has an implicit conversion operator from TError to Result<TValue, TError> which allows directly returning error objects from methods that return Result types.
```

---

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:96-103
Timestamp: 2025-05-18T14:11:20.141Z
Learning: The Result<TValue, TError> struct in Altinn.Notifications provides an implicit conversion operator from TError to Result<TValue, TError>, which allows directly returning error objects from methods that return Result types without explicitly wrapping them.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer><details>
<summary>🧩 Analysis chain</summary>

The file `src/Altinn.Notifications.Core/Shared/Result.cs` contains:

```csharp
namespace Altinn.Notifications.Core.Shared;

/// <summary>
/// A result which can be either a success with a value or an error with an error object.
/// </summary>
/// <typeparam name="TValue">The type of the value in case of success.</typeparam>
/// <typeparam name="TError">The type of the error in case of an error.</typeparam>
/// <remarks>Created based on <see href="https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/CSharpFunctionalExtensions/Result/Result.cs" />.</remarks>
public readonly struct Result<TValue, TError>
{
    private readonly TValue? _value;
    private readonly TError? _error;
    private readonly bool _isSuccess;

    /// <summary>
    /// Gets a value indicating whether this result is an error.
    /// </summary>
    public bool IsError => !_isSuccess;

    /// <summary>
    /// Gets a value indicating whether this result is a success.
    /// </summary>
    public bool IsSuccess => _isSuccess;

    /// <summary>
    /// Gets the error value if this result is an error, or null if it's a success.
    /// </summary>
    public TError? Error => _error;

    /// <summary>
    /// Gets the success value if this result is a success, or null if it's an error.
    /// </summary>
    public TValue? Value => _value;

    private Result(bool isSuccess, TValue? value, TError? error)
    {
        _isSuccess = isSuccess;
        _value = value;
        _error = error;
    }

    /// <summary>
    /// Performs pattern matching on the result.
    /// </summary>
    /// <typeparam name="T">The return type of the pattern matching.</typeparam>
    /// <param name="onSuccess">Function to call when the result is a success.</param>
    /// <param name="onError">Function to call when the result is an error.</param>
    /// <returns>The result of the corresponding function.</returns>
    public T Match<T>(Func<TValue, T> onSuccess, Func<TError, T> onError)
    {
        return _isSuccess ? onSuccess(_value!) : onError(_error!);
    }

    /// <summary>
    /// Creates a success result with the given value.
    /// </summary>
    /// <param name="value">The value to wrap in a success result.</param>
    /// <returns>A new success result wrapping the value.</returns>
    public static implicit operator Result<TValue, TError>(TValue value)
    {
        return new Result<TValue, TError>(true, value, default);
    }

    /// <summary>
    /// Creates an error result with the given error.
    /// </summary>
    /// <param name="error">The error to wrap in an error result.</param>
    /// <returns>A new error result wrapping the error.</returns>
    public static implicit operator Result<TValue, TError>(TError error)
    {
        return new Result<TValue, TError>(false, default, error);
    }
}
```



@Ahmed-Ghanam You're absolutely right. I've verified the code in `Result.cs` and found the implicit conversion operator you mentioned:

```csharp
public static implicit operator Result<TValue, TError>(TError error)
{
    return new Result<TValue, TError>(false, default, error);
}
```

This operator allows `ServiceError` values to be implicitly converted to `Result<NotificationOrderChainResponse, ServiceError>` with `IsSuccess = false`, making the current implementation perfectly valid. Thank you for the clarification!



---

🏁 Script executed:
```
#!/bin/bash
# Find the Result.cs file
cat src/Altinn.Notifications.Core/Shared/Result.cs
```

Length of output: 2585

---



</details>

@Ahmed-Ghanam You're absolutely right. I've examined the `Result.cs` file and confirmed there is indeed an implicit conversion operator defined:

```csharp
/// <summary>
/// Implicit operator used when creating an instance of Result when assigning an error value.
/// </summary>
/// <param name="error">An object of the type indicating failure.</param>
public static implicit operator Result<TValue, TError>(TError error) => new(error);
```

This operator allows a `ServiceError` to be implicitly converted to a `Result<NotificationOrderChainResponse, ServiceError>` with `IsError = true`, making the current implementation perfectly valid. The code is using this pattern throughout the codebase for clean error handling.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets from `src/Altinn.Notifications.Core/Shared/Result.cs` (lines 14-26)
```csharp
private Result(TValue value)
{
    IsError = false;
    _value = value;
    _error = default;
}

private Result(TError error)
{
    IsError = true;
    _value = default;
    _error = error;
}
```
- These constructors initialize a `Result<TValue, TError>` instance either with a value (success) or an error (failure).
- The constructor taking `TError` sets `IsError` to true and stores the error.
- The implicit conversion operator from `TError` to `Result<TValue, TError>` is likely implemented here or nearby (not shown in snippet), enabling returning an error directly where a `Result` is expected.

---

### Relevant snippets from `src/Altinn.Notifications.Core/Services/OrderRequestService.cs` (lines 70-130 approx)
- The method `RegisterNotificationOrderChain` returns `Task<Result<NotificationOrderChainResponse, ServiceError>>`.
- It calls `CreateMainNotificationOrderAsync` and `CreateReminderNotificationOrdersAsync`, both returning `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.
- When these methods return an error, the code returns `mainResult.Error` or `remindersResult.Error` directly, relying on implicit conversion from `ServiceError` to `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.
- This implicit conversion operator from `TError` to `Result<TValue, TError>` is not visible in the snippet but is used here.

---

### Relevant snippets from `src/Altinn.Notifications.Core/Shared/ServiceError.cs` (lines 6-35)
```csharp
public class ServiceError
{
    public int ErrorCode { get; private set; }
    public string? ErrorMessage { get; private set; }

    public ServiceError(int errorCode, string errorMessage)
    {
        ErrorCode = errorCode;
        ErrorMessage = errorMessage;
    }

    public ServiceError(int errorCode)
    {
        ErrorCode = errorCode;
    }
}
```
- `ServiceError` is the error type used as `TError` in `Result<TValue, TError>`.
- It encapsulates an error code (HTTP status code) and an optional error message.

---

### Summary of `Result<TValue, TError>` implicit conversion operator context
- The `Result<TValue, TError>` struct has constructors for success and error states.
- It likely defines an implicit conversion operator from `TError` to `Result<TValue, TError>`, allowing returning an error instance directly where a `Result` is expected.
- This operator is used in `OrderRequestService` methods like `RegisterNotificationOrderChain` to return errors from service methods without explicitly wrapping them.
- The `ServiceError` class is the error type used in these results, representing service-level errors with HTTP status codes and messages.

---

### Additional context from `OrderRequestService.cs`
- Methods like `CreateMainNotificationOrderAsync` and `CreateReminderNotificationOrdersAsync` return `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.
- When validation fails (e.g., missing contact info), they return `new ServiceError(...)`.
- The caller methods return these errors directly, relying on the implicit conversion operator to convert `ServiceError` to `Result<NotificationOrder, ServiceError>` or `Result<List<NotificationOrder>, ServiceError>`.

---

### Summary for human reviewer
- The implicit conversion operator from `TError` to `Result<TValue, TError>` is defined in the `Result` struct (not shown in snippet).
- It enables returning an error instance (like `ServiceError`) directly as a `Result` without explicit wrapping.
- This pattern is used in `OrderRequestService` to simplify error propagation in async methods returning `Result`.
- The `ServiceError` class represents the error payload in these results.

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:96-103
Timestamp: 2025-05-18T14:11:20.141Z
Learning: The Result<TValue, TError> struct in Altinn.Notifications has an implicit conversion operator from TError to Result<TValue, TError> which allows directly returning error objects from methods that return Result types.
```

---

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:96-103
Timestamp: 2025-05-18T14:11:20.141Z
Learning: The Result<TValue, TError> struct in Altinn.Notifications provides an implicit conversion operator from TError to Result<TValue, TError>, which allows directly returning error objects from methods that return Result types without explicitly wrapping them.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T14:11:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,119 +85,283 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     }
 
     /// <inheritdoc/>
-    public async Task<NotificationOrderChainResponse> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
+    public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        var mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
+        {
+            return mainResult.Error;
+        }
 
-        var reminderOrders = await CreateNotificationOrders(
-            orderRequest.Reminders,
-            orderRequest.Creator,
-            currentTime,
-            cancellationToken);
+        // 4. Create reminders
+        var remindersResult = await CreateReminderNotificationOrdersAsync(orderRequest.Reminders, orderRequest.Creator, currentTime, cancellationToken);
+        if (remindersResult.IsError && remindersResult.Error != null)
+        {
+            return remindersResult.Error;
+        }
 
-        List<NotificationOrder> savedOrders = await _repository.Create(orderRequest, mainOrder, reminderOrders, cancellationToken);
+        // 5. Create the response
+        return await CreateChainResponseAsync(orderRequest, mainResult.Value, remindersResult.Value, cancellationToken);
+    }
 
-        if (savedOrders == null || savedOrders.Count == 0)
+    /// <summary>
+    /// Creates the primary <see cref="NotificationOrder"/> for a notification chain by processing
+    /// recipient information, validating contact details, and configuring message templates.
+    /// </summary>
+    /// <param name="orderRequest">
+    /// The incoming chain request containing recipient information, templates, and other notification parameters.
+    /// </param>
+    /// <param name="currentTime">
+    /// The UTC timestamp to set as the creation time of the notification order.
+    /// </param>
+    /// <param name="cancellationToken">
+    /// A token that can be used to request cancellation of the asynchronous operation.
+    /// </param>
+    /// <returns>
+    /// A <see cref="Result{TValue,TError}"/> containing either:
+    /// <list type="bullet">
+    /// <item>
+    /// <description>A successful result with <see cref="Result{TValue,TError}.Value"/> containing the fully configured
+    /// <see cref="NotificationOrder"/> ready for persistence and processing</description>
+    /// </item>
+    /// <item>
+    /// <description>A failed result with <see cref="Result{TValue,TError}.Error"/> containing a
+    /// <see cref="ServiceError"/> with status code and detailed error message about the failure reason</description>
+    /// </item>
+    /// </list>
+    /// </returns>
+    /// <remarks>
+    /// This method performs recipient validation, template preparation, and order creation:
+    /// <list type="number">
+    /// <item><description>Extracts delivery components from the recipient configuration</description></item>
+    /// <item><description>Validates recipient contact information through lookup services</description></item>
+    /// <item><description>Applies default sender information where needed</description></item>
+    /// <item><description>Constructs a complete notification order with all required properties</description></item>
+    /// </list>
+    /// </remarks>
+    /// <exception cref="OperationCanceledException">
+    /// Thrown when the operation is canceled through the provided <paramref name="cancellationToken"/>.
+    /// </exception>
+    private async Task<Result<NotificationOrder, ServiceError>> CreateMainNotificationOrderAsync(NotificationOrderChainRequest orderRequest, DateTime currentTime, CancellationToken cancellationToken)
+    {
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var (recipients, templates, channel, ignoreReservation, resourceId, sendingTimePolicyForSms) = ExtractDeliveryComponents(orderRequest.Recipient);
+
+        var lookupResult = await GetRecipientLookupResult(recipients, channel, GetSanitizedResourceId(resourceId));
+
+        if (lookupResult?.MissingContact?.Count > 0)
         {
-            throw new InvalidOperationException("Failed to create the notification order chain.");
+            return new ServiceError(422, $"Missing contact information for recipient(s): {string.Join(", ", lookupResult.MissingContact)}");
         }
 
-        // Get the main order (first in the list)
-        var savedMainOrder = savedOrders[0];
+        templates = SetSenderIfNotDefined(templates);
 
-        // Create and return the response
-        return new NotificationOrderChainResponse
+        return new NotificationOrder
         {
-            OrderChainId = orderRequest.OrderChainId,
-            OrderChainReceipt = new NotificationOrderChainReceipt
-            {
-                ShipmentId = savedMainOrder.Id,
-                SendersReference = savedMainOrder.SendersReference,
-                Reminders = savedOrders.Count > 1
-                    ? [.. savedOrders
-                        .Where(e => e.Id != savedMainOrder.Id)
-                        .Select(order => new NotificationOrderChainShipment
-                        {
-                            ShipmentId = order.Id,
-                            SendersReference = order.SendersReference
-                        })]
-                    : null
-            }
+            Created = currentTime,
+            Templates = templates,
+            ResourceId = resourceId,
+            Recipients = recipients,
+            Type = orderRequest.Type,
+            Id = orderRequest.OrderId,
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: Ahmed-Ghanam
body: We need to remove the prefix only for the lookup call, otherwise the full value must be persisted in the data store.
created_at: 2025-05-18T14:12:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,119 +85,283 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     }
 
     /// <inheritdoc/>
-    public async Task<NotificationOrderChainResponse> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
+    public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        var mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
+        {
+            return mainResult.Error;
+        }
 
-        var reminderOrders = await CreateNotificationOrders(
-            orderRequest.Reminders,
-            orderRequest.Creator,
-            currentTime,
-            cancellationToken);
+        // 4. Create reminders
+        var remindersResult = await CreateReminderNotificationOrdersAsync(orderRequest.Reminders, orderRequest.Creator, currentTime, cancellationToken);
+        if (remindersResult.IsError && remindersResult.Error != null)
+        {
+            return remindersResult.Error;
+        }
 
-        List<NotificationOrder> savedOrders = await _repository.Create(orderRequest, mainOrder, reminderOrders, cancellationToken);
+        // 5. Create the response
+        return await CreateChainResponseAsync(orderRequest, mainResult.Value, remindersResult.Value, cancellationToken);
+    }
 
-        if (savedOrders == null || savedOrders.Count == 0)
+    /// <summary>
+    /// Creates the primary <see cref="NotificationOrder"/> for a notification chain by processing
+    /// recipient information, validating contact details, and configuring message templates.
+    /// </summary>
+    /// <param name="orderRequest">
+    /// The incoming chain request containing recipient information, templates, and other notification parameters.
+    /// </param>
+    /// <param name="currentTime">
+    /// The UTC timestamp to set as the creation time of the notification order.
+    /// </param>
+    /// <param name="cancellationToken">
+    /// A token that can be used to request cancellation of the asynchronous operation.
+    /// </param>
+    /// <returns>
+    /// A <see cref="Result{TValue,TError}"/> containing either:
+    /// <list type="bullet">
+    /// <item>
+    /// <description>A successful result with <see cref="Result{TValue,TError}.Value"/> containing the fully configured
+    /// <see cref="NotificationOrder"/> ready for persistence and processing</description>
+    /// </item>
+    /// <item>
+    /// <description>A failed result with <see cref="Result{TValue,TError}.Error"/> containing a
+    /// <see cref="ServiceError"/> with status code and detailed error message about the failure reason</description>
+    /// </item>
+    /// </list>
+    /// </returns>
+    /// <remarks>
+    /// This method performs recipient validation, template preparation, and order creation:
+    /// <list type="number">
+    /// <item><description>Extracts delivery components from the recipient configuration</description></item>
+    /// <item><description>Validates recipient contact information through lookup services</description></item>
+    /// <item><description>Applies default sender information where needed</description></item>
+    /// <item><description>Constructs a complete notification order with all required properties</description></item>
+    /// </list>
+    /// </remarks>
+    /// <exception cref="OperationCanceledException">
+    /// Thrown when the operation is canceled through the provided <paramref name="cancellationToken"/>.
+    /// </exception>
+    private async Task<Result<NotificationOrder, ServiceError>> CreateMainNotificationOrderAsync(NotificationOrderChainRequest orderRequest, DateTime currentTime, CancellationToken cancellationToken)
+    {
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var (recipients, templates, channel, ignoreReservation, resourceId, sendingTimePolicyForSms) = ExtractDeliveryComponents(orderRequest.Recipient);
+
+        var lookupResult = await GetRecipientLookupResult(recipients, channel, GetSanitizedResourceId(resourceId));
+
+        if (lookupResult?.MissingContact?.Count > 0)
         {
-            throw new InvalidOperationException("Failed to create the notification order chain.");
+            return new ServiceError(422, $"Missing contact information for recipient(s): {string.Join(", ", lookupResult.MissingContact)}");
         }
 
-        // Get the main order (first in the list)
-        var savedMainOrder = savedOrders[0];
+        templates = SetSenderIfNotDefined(templates);
 
-        // Create and return the response
-        return new NotificationOrderChainResponse
+        return new NotificationOrder
         {
-            OrderChainId = orderRequest.OrderChainId,
-            OrderChainReceipt = new NotificationOrderChainReceipt
-            {
-                ShipmentId = savedMainOrder.Id,
-                SendersReference = savedMainOrder.SendersReference,
-                Reminders = savedOrders.Count > 1
-                    ? [.. savedOrders
-                        .Where(e => e.Id != savedMainOrder.Id)
-                        .Select(order => new NotificationOrderChainShipment
-                        {
-                            ShipmentId = order.Id,
-                            SendersReference = order.SendersReference
-                        })]
-                    : null
-            }
+            Created = currentTime,
+            Templates = templates,
+            ResourceId = resourceId,
+            Recipients = recipients,
+            Type = orderRequest.Type,
+            Id = orderRequest.OrderId,
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: coderabbitai[bot]
body: @Ahmed-Ghanam Understood! I see that the current implementation already does exactly that - it only sanitizes the resourceId for the lookup call while preserving the full value in the data store. This is the correct approach based on your requirements.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:156-174
Timestamp: 2025-05-18T14:12:25.106Z
Learning: The `urn:altinn:resource:` prefix should only be removed from resourceId when making contact point lookup calls, but the full unsanitized value must be persisted in the data store. This is intentional behavior in the OrderRequestService.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@Ahmed-Ghanam Understood! I see that the current implementation already does exactly that - it only sanitizes the resourceId for the lookup call while preserving the full value in the data store. This is the correct approach based on your requirements.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Ahmed-Ghanam
PR: Altinn/altinn-notifications#851
File: src/Altinn.Notifications.Core/Services/OrderRequestService.cs:156-174
Timestamp: 2025-05-18T14:12:25.106Z
Learning: The `urn:altinn:resource:` prefix should only be removed from resourceId when making contact point lookup calls, but the full unsanitized value must be persisted in the data store. This is intentional behavior in the OrderRequestService.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-18T14:12:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+﻿namespace Altinn.Notifications.Core.Enums;
+
+/// <summary>
+/// Defines the different types of an order.
+/// </summary>
+public enum OrderTypes : uint
path: src/Altinn.Notifications.Core/Enums/OrderTypes.cs
user: login: eskebab
body: I would suggest the name OrderType
created_at: 2025-05-19T06:50:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,7 +67,8 @@ public NotificationOrder(
         List<Recipient> recipients,
         bool? ignoreReservation,
         string? resourceId,
-        Uri? conditionEndpoint)
+        Uri? conditionEndpoint,
+        OrderTypes type)
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
user: login: eskebab
body: We could create a new issue where we get rid of this constructor and just use an object initialiser
created_at: 2025-05-19T07:40:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+﻿namespace Altinn.Notifications.Core.Enums;
+
+/// <summary>
+/// Defines the different types of an order.
+/// </summary>
+public enum OrderTypes : uint
path: src/Altinn.Notifications.Core/Enums/OrderTypes.cs
user: login: eskebab
body: Other enums are singular. AddressType, SmsNotificationResultType etc
created_at: 2025-05-19T07:42:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -67,12 +67,26 @@ public async Task<ActionResult<NotificationDeliveryManifestExt>> GetById([FromRo
                 },
                 error =>
                 {
-                    return StatusCode(error.ErrorCode, error.ErrorMessage);
+                    var problemDetails = new ProblemDetails
+                    {
+                        Title = "Failed to retrieve shipment information",
+                        Detail = error.ErrorMessage,
+                        Status = error.ErrorCode
+                    };
+
+                    return StatusCode(error.ErrorCode, problemDetails);
                 });
         }
         catch (OperationCanceledException)
         {
-            return StatusCode(499, "Request terminated - The client disconnected or cancelled the request before the server could complete processing");
+            var problemDetails = new ProblemDetails
path: src/Altinn.Notifications/Controllers/ShipmentController.cs
user: login: eskebab
body: I suggest we make an issue to create a middleware that catches this type of exception and returns a problemDetails object
created_at: 2025-05-19T07:49:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,9 @@
+DO $$
+BEGIN
+    IF NOT EXISTS (SELECT 1 
+                   FROM pg_type
+                   WHERE typname = 'notificationordertypes'
path: src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql
user: login: eskebab
body: same, I would rather use singular than plural
created_at: 2025-05-19T07:56:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -206,6 +227,11 @@ public NotificationOrderChainRequestBuilder SetSendersReference(string? sendersR
         /// </summary>
         public NotificationOrderChainRequest Build()
         {
+            if (_type != OrderTypes.Notification)
+            {
+                throw new InvalidOperationException("Invalid type used.");
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs
user: login: eskebab
body: this exception is never caught so it will result in a 500 with no explanation. Is this intentional as it's handled by the validator?
created_at: 2025-05-19T08:40:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -87,103 +87,73 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     /// <inheritdoc/>
     public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        Result<NotificationOrder, ServiceError> mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
-
-        if (mainOrder.IsError && mainOrder.Error != null)
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
         {
-            return mainOrder.Error;
+            return mainResult.Error;
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: eskebab
body: it's still the main order. I would rather use mainOrder or mainOrderResult.
created_at: 2025-05-19T08:42:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+﻿namespace Altinn.Notifications.Core.Enums;
+
+/// <summary>
+/// Defines the different types of an order.
+/// </summary>
+public enum OrderTypes : uint
path: src/Altinn.Notifications.Core/Enums/OrderTypes.cs
user: login: Ahmed-Ghanam
body: I renamed the enum to `OrderType`
created_at: 2025-05-20T04:51:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,7 +67,8 @@ public NotificationOrder(
         List<Recipient> recipients,
         bool? ignoreReservation,
         string? resourceId,
-        Uri? conditionEndpoint)
+        Uri? conditionEndpoint,
+        OrderTypes type)
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs
user: login: Ahmed-Ghanam
body: This represents a form of technical debt that can be addressed either independently or as part of implementing new functionality involving this constructor.
created_at: 2025-05-20T04:54:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -67,12 +67,26 @@ public async Task<ActionResult<NotificationDeliveryManifestExt>> GetById([FromRo
                 },
                 error =>
                 {
-                    return StatusCode(error.ErrorCode, error.ErrorMessage);
+                    var problemDetails = new ProblemDetails
+                    {
+                        Title = "Failed to retrieve shipment information",
+                        Detail = error.ErrorMessage,
+                        Status = error.ErrorCode
+                    };
+
+                    return StatusCode(error.ErrorCode, problemDetails);
                 });
         }
         catch (OperationCanceledException)
         {
-            return StatusCode(499, "Request terminated - The client disconnected or cancelled the request before the server could complete processing");
+            var problemDetails = new ProblemDetails
path: src/Altinn.Notifications/Controllers/ShipmentController.cs
user: login: Ahmed-Ghanam
body: This represents also a form of technical debt that can be addressed either independently or as part of implementing new functionality.
created_at: 2025-05-20T04:55:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,9 @@
+DO $$
+BEGIN
+    IF NOT EXISTS (SELECT 1 
+                   FROM pg_type
+                   WHERE typname = 'notificationordertypes'
path: src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql
user: login: Ahmed-Ghanam
body: I renamed this type to `notificationordertype`
created_at: 2025-05-20T04:59:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -206,6 +227,11 @@ public NotificationOrderChainRequestBuilder SetSendersReference(string? sendersR
         /// </summary>
         public NotificationOrderChainRequest Build()
         {
+            if (_type != OrderTypes.Notification)
+            {
+                throw new InvalidOperationException("Invalid type used.");
path: src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs
user: login: Ahmed-Ghanam
body: To prevent HTTP 500 errors and provide a more meaningful response to the client, I included the following exception handling block in the `Post` action defined in `FutureOrdersController`:

```csharp
catch (InvalidOperationException ex)
{
    var problemDetails = new ProblemDetails
    {
        Status = 400,
        Title = "Invalid notification request",
        Detail = ex.Message
    };
    return BadRequest(problemDetails);
}
```
created_at: 2025-05-20T05:11:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -87,103 +87,73 @@ public async Task<NotificationOrderRequestResponse> RegisterNotificationOrder(No
     /// <inheritdoc/>
     public async Task<Result<NotificationOrderChainResponse, ServiceError>> RegisterNotificationOrderChain(NotificationOrderChainRequest orderRequest, CancellationToken cancellationToken = default)
     {
+        // 1. Get the current time
         DateTime currentTime = _dateTime.UtcNow();
 
+        // 2. Early cancellation if someone’s already cancelled
         cancellationToken.ThrowIfCancellationRequested();
 
-        Result<NotificationOrder, ServiceError> mainOrder = await CreateNotificationOrder(
-            orderRequest.Recipient,
-            orderRequest.OrderId,
-            orderRequest.SendersReference,
-            orderRequest.RequestedSendTime,
-            orderRequest.Creator,
-            currentTime,
-            orderRequest.ConditionEndpoint);
-
-        if (mainOrder.IsError && mainOrder.Error != null)
+        // 3. Create the main order
+        var mainResult = await CreateMainNotificationOrderAsync(orderRequest, currentTime, cancellationToken);
+        if (mainResult.IsError && mainResult.Error != null)
         {
-            return mainOrder.Error;
+            return mainResult.Error;
path: src/Altinn.Notifications.Core/Services/OrderRequestService.cs
user: login: Ahmed-Ghanam
body: I renamed this variable to `mainOrderResult`
created_at: 2025-05-20T05:16:09Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-15T12:43:08Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Walkthrough

This change introduces a new `OrderType` enum to distinguish between notification orders and reminders throughout the codebase and database schema. It updates models, repositories, services, mappers, and tests to support and propagate this type information. Database migrations add the new type to relevant tables and functions, and error handling in some controllers is improved for structured responses.

## Changes

| Files/Paths (Grouped)                                                                                      | Change Summary |
|------------------------------------------------------------------------------------------------------------|---------------|
| `src/Altinn.Notifications.Core/Enums/OrderType.cs`                                                         | Added new public enum `OrderType` with values `Notification` and `Reminder`. |
| `src/Altinn.Notifications.Core/Models/Orders/IBaseNotificationOrder.cs`<br>`NotificationOrder.cs`<br>`NotificationOrderWithStatus.cs`<br>`NotificationOrderChainRequest.cs`<br>`NotificationReminder.cs` | Added `Type` property of type `OrderType` to interfaces and classes; updated constructors and builders to handle the new property. |
| `src/Altinn.Notifications.Core/Services/OrderRequestService.cs`                                            | Refactored to handle `OrderType` in order creation, reminders, and error handling; added/removed methods and improved documentation. |
| `src/Altinn.Notifications.Persistence/Migration/v0.43/01-new-type.sql`                                     | Introduced new PostgreSQL enum type `notificationordertype` with values `Notification` and `Reminder`. |
| `src/Altinn.Notifications.Persistence/Migration/v0.43/02-alter-table.sql`                                  | Conditionally added a new non-nullable `type` column of enum type to `notifications.orders` table. |
| `src/Altinn.Notifications.Persistence/Migration/FunctionsAndProcedures/getshipmenttracking.sql`<br>`insertorder.sql`<br>`v0.43/01-functions-and-procedures.sql` | Added/updated SQL functions and procedures to support the new `type` column and propagate order type in tracking and insertion. |
| `src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs`<br>`NotificationDeliveryManifestRepository.cs` | Updated SQL and repository logic to handle the new `type` column and pass/read `OrderType` values. |
| `src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs`                                         | Updated mapping logic to set `Type` property for orders and reminders. |
| `src/Altinn.Notifications/Controllers/ShipmentController.cs`                                               | Enhanced error handling to return structured `ProblemDetails` objects. |
| `src/Altinn.Notifications/Controllers/FutureOrdersController.cs`                                          | Added catch block for `InvalidOperationException` to return 400 Bad Request with problem details. |
| `test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/NotificationDeliveryManifestRepositoryTests.cs`<br>`OrderRepositoryTests.cs`<br>`Notifications/OrdersController/OrdersControllerTests.cs` | Updated tests to set and assert the `Type` property for orders and reminders, and to verify type-based queries. |
| `test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/OrderRequestServiceTests.cs`           | Updated and added tests to verify correct handling of `OrderType`, including new error scenarios and type propagation in order chains. |
| `test/Altinn.Notifications.Tests/Notifications/TestingMappers/NotificationOrderChainMapperTests.cs`        | Added/updated tests to assert correct mapping of `OrderType` and validation logic for main/reminder types. |
| `test/Altinn.Notifications.Tests/Notifications.Core/TestingModels/NotificationOrderTests.cs`               | Updated test setup and JSON to include `Type`; removed obsolete deserialization test. |
| `test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs` | Added test for `InvalidOperationException` handling returning 400 Bad Request with problem details; minor formatting and cleanup. |

## Possibly related PRs

- [Altinn/altinn-notifications#823](https://github.com/Altinn/altinn-notifications/pull/823): Refactors `RegisterNotificationOrderChain` in `OrderRequestService.cs` to use explicit `Result`-based error handling and updates related private methods, directly overlapping with this PR's changes.
- [Altinn/altinn-notifications#789](https://github.com/Altinn/altinn-notifications/pull/789): Modifies error handling and response behavior in `FutureOrdersController.Post`, related to improved error responses and status codes.

## Suggested reviewers

- eskebab
- tba76

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details>
> <summary>⚡️ AI Code Reviews for VS Code, Cursor, Windsurf</summary>
> 
> CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
> Learn more [here](http://coderabbit.ai/ide).
> 
> </details>

---

> [!NOTE]
> <details>
> <summary>⚡️ Faster reviews with caching</summary>
> 
> CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure `Review - Disable Cache` at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the `Data Retention` setting under your Organization Settings.
> Enjoy the performance boost—your workflow just got faster.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 6c7d2dbd5834c0167c1e92c2a1c7441324928154 and 6cb5057341890a4700ae0160cf52a5db926914a3.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs` (5 hunks)
* `src/Altinn.Notifications/Controllers/FutureOrdersController.cs` (1 hunks)
* `test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs` (4 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* src/Altinn.Notifications.Core/Models/Orders/NotificationOrderChainRequest.cs

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs (5)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications.Core/Services/OrderRequestService.cs (7)</summary>

* `Task` (48-79)
* `Task` (82-85)
* `Task` (88-112)
* `Task` (152-183)
* `Task` (229-271)
* `Task` (312-349)
* `Task` (361-410)

</details>
<details>
<summary>src/Altinn.Notifications/Models/NotificationRecipientExt.cs (1)</summary>

* `NotificationRecipientExt` (16-55)

</details>
<details>
<summary>src/Altinn.Notifications/Mappers/NotificationOrderChainMapper.cs (2)</summary>

* `RecipientEmail` (122-129)
* `NotificationOrderChainRequest` (27-63)

</details>
<details>
<summary>src/Altinn.Notifications/Models/Email/RecipientEmailExt.cs (1)</summary>

* `RecipientEmailExt` (13-34)

</details>
<details>
<summary>src/Altinn.Notifications/Controllers/FutureOrdersController.cs (1)</summary>

* `FutureOrdersController` (35-39)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Build, test & analyze
* GitHub Check: Analyze (csharp)

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>src/Altinn.Notifications/Controllers/FutureOrdersController.cs (1)</summary>

`102-111`: **Improved error handling for invalid requests.**

The new catch block for `InvalidOperationException` enhances the API's error handling by providing a clear, structured response when the request mapping process fails. This properly handles cases where validation passes but the request fails during mapping due to issues like an empty `IdempotencyId`.

</details>
<details>
<summary>test/Altinn.Notifications.IntegrationTests/Notifications/FutureOrdersController/FutureOrdersControllerTests.cs (3)</summary>

`792-841`: **Good test coverage for the new error handling.**

This test correctly verifies that when the mapper throws an `InvalidOperationException` due to invalid input (empty `IdempotencyId`), the controller returns a 400 Bad Request with appropriate problem details. It also ensures the order service is never called, which is the expected behavior when mapping fails.

---

`930-930`: **Method signature improvement.**

Adding default parameters to the `CreateNotificationOrderChainResponse` method improves code readability and simplifies call sites.

---

`966-966`: **Method signature improvement.**

Adding nullable parameters to the `GetTestClient` method improves flexibility when using this helper in tests.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings
<details open="true">
<summary>🧪 Generate Unit Tests</summary>

- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Create PR with Unit Tests
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Commit Unit Tests in branch `bugfix/834-provide-correct-type`
- [ ] <!-- {"checkboxId": "07f1e7d6-8a8e-4e23-9900-8731c2c87f58", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Post Copyable Unit Tests in Comment

</details>

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Altinn/altinn-notifications&utm_content=851):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai auto-generate unit tests` to generate unit tests for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: Ahmed-Ghanam
created_at: 2025-05-19T04:54:41Z
body: @coderabbitai summarize
author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-05-20T14:45:55Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Altinn_altinn-notifications&pullRequest=851) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=Altinn_altinn-notifications&pullRequest=851&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Altinn_altinn-notifications&pullRequest=851&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Altinn_altinn-notifications&pullRequest=851&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [99.3% Coverage on New Code](https://sonarcloud.io/component_measures?id=Altinn_altinn-notifications&pullRequest=851&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Altinn_altinn-notifications&pullRequest=851&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Altinn_altinn-notifications&pullRequest=851)


author_association: NONE