diff --git a/Documentation/working_notes.md b/Documentation/working_notes.md
index 91b76b4a0db6dd3058c0fe7392d4bf4edd2a3c84..089b933e93f1064fa4bc9dc0825798d333bf6d8c 100644
--- a/Documentation/working_notes.md
+++ b/Documentation/working_notes.md
@@ -25,13 +25,24 @@
 
 ## Links
 
+### Documentation
+
 - [SDK-Konzept im Wiki](https://wiki.fit-connect.fitko.dev/de/Konzeption/Konzeption_SDK)
 - [inoffizielles Python-SDK](https://github.com/codedust/fitconnect-sdk-python)
 - [Project management](https://wiki.fit-connect.fitko.dev/de/PM_PUBLIC/Projektvorgehensmodell)
 - [Wiki SDK Description](https://wiki.fit-connect.fitko.dev/de/PM_PUBLIC/Epics/SDK_Initialisierung)
 - [Containing GitLab](https://git.fitko.de/)
 - [Board filtered for SDK](https://git.fitko.de/fit-connect/planning/-/boards/44?label_name%5B%5D=component%3A%3ASDK)
-- [Documentation](https://docs.fitko.de/fit-connect/docs/getting-started/first-steps/)
+- [FitConnect First Steps](https://docs.fitko.de/fit-connect/docs/getting-started/first-steps/)
 - [Security Event Token Requirements](https://wiki.fit-connect.fitko.dev/de/Konzeption/Security_Event_Token_Future)
 - [glossary](https://docs.fitko.de/fit-connect/docs/glossary/)
 
+### Helper
+- [Create C# class from JSON schema](https://app.quicktype.io/?l=csharp)
+
+## Values for testing
+
+| Topic              | Value          | Description                             |
+|:-------------------|:---------------|:----------------------------------------|
+| Leika Key          | 99099002067003 | Deutsche Staatsangehörigkeit beantragen |
+| Gemeinde Schlüssel | 09 3 72 126    | Furth im Wald                           |
\ No newline at end of file
diff --git a/DummyClient/Program.cs b/DummyClient/Program.cs
index c60290a01226fe8d94fc2f2aab570b5a1510fcde..6152e9850e85ec03a55979738eaade640c1805dd 100644
--- a/DummyClient/Program.cs
+++ b/DummyClient/Program.cs
@@ -9,6 +9,7 @@ var clientSecret = "";
 PublicKey publicKey;
 ILogger _logger;
 Client client;
+X509Certificate2 certificate;
 
 /*
  * The easy way to call the FitConnect API
@@ -29,8 +30,8 @@ async Task AbstractCall() {
 void FluentSenderCall() {
     client.Sender
         .Authenticate(clientId!, clientSecret!)
-        .CreateSubmission(new Submission())
-        .UploadAttachments(new List<Attachment>())
+        .CreateSubmission(new Submission { Attachments = new List<Attachment>() })
+        .UploadAttachments()
         .SendSubmission(new Metadata(), new Data());
 }
 
@@ -61,7 +62,7 @@ void FluentSubscriberCall() {
 async Task DetailSenderCall() {
     var sender =
         new Sender(
-            FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development));
+            FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development), certificate);
 
     var submissionDto = sender.AddSubmission(new Submission());
     var encryptedAttachments = sender.Encrypt(publicKey, new List<Attachment>());
@@ -79,7 +80,7 @@ async Task DetailSenderCall() {
 async Task DetailSubscriberCall() {
     var subscriber =
         new Subscriber(
-            FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development));
+            FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development), certificate);
     var submissions = await subscriber.GetSubmissionsAsync("destinationId");
     /*
      ....
diff --git a/E2ETests/SenderTest.cs b/E2ETests/SenderTest.cs
index 1a08672b9973011adaaee9371d281788b3ce3d5b..c5010494aa61c15ff044c161cbfde0b8bbac87bc 100644
--- a/E2ETests/SenderTest.cs
+++ b/E2ETests/SenderTest.cs
@@ -1,7 +1,11 @@
 using System;
 using System.IO;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
 using FitConnect;
+using FitConnect.Security;
 using FluentAssertions;
+using Microsoft.IdentityModel.Tokens;
 using Newtonsoft.Json;
 using NUnit.Framework;
 
@@ -44,7 +48,8 @@ public class SenderTest {
     [SetUp]
     public void Setup() {
         _sender = new Sender(
-            FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development));
+            FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development),
+            RsaEncryption.CreateSelfSignedCertificate());
     }
 
     [Test]
diff --git a/FitConnect/BaseClasses/FunctionalBaseClass.cs b/FitConnect/BaseClasses/FunctionalBaseClass.cs
index 0483bf91e4eeec23934e796155c68e7d0290e239..f8a291fdef8cf1e032599de57e31912dd0294b44 100644
--- a/FitConnect/BaseClasses/FunctionalBaseClass.cs
+++ b/FitConnect/BaseClasses/FunctionalBaseClass.cs
@@ -11,24 +11,26 @@ public abstract class FunctionalBaseClass {
     protected readonly FitConnectApiService ApiService;
     public readonly IEncryption Encryption;
     protected readonly ILogger? Logger;
+    protected readonly X509Certificate2 Certificate;
     internal Client Owner { get; set; }
 
 
     /// <summary>
     ///     Constructor for the FunctionalBaseClass
     /// </summary>
-    /// <param name="logger">ILogger implementation</param>
     /// <param name="endpoints">FitConnect endpoints</param>
     /// <param name="certificate">The Encryption certificate</param>
+    /// <param name="logger">ILogger implementation</param>
     /// <example>
     ///     new Sender(logger, FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development))
     /// </example>
-    protected FunctionalBaseClass(ILogger? logger, FitConnectEndpoints? endpoints,
-        X509Certificate2? certificate) {
+    protected FunctionalBaseClass(FitConnectEndpoints? endpoints,
+        X509Certificate2 certificate, ILogger? logger) {
         Endpoints = endpoints ??
                     FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development);
 
         Logger = logger;
+        Certificate = certificate;
         Encryption = new RsaEncryption(logger, certificate);
         ApiService = new FitConnectApiService(Endpoints, logger);
     }
@@ -43,7 +45,8 @@ public abstract class FunctionalBaseClass {
     /// <param name="clientSecret"></param>
     /// <param name="scope"></param>
     /// <returns></returns>
-    public Task<OAuthAccessToken?> AuthenticateAsync(string clientId, string clientSecret, string? scope) {
+    public Task<OAuthAccessToken?> AuthenticateAsync(string clientId, string clientSecret,
+        string? scope) {
         return ApiService.OAuthService.AuthenticateAsync(clientId, clientSecret, scope);
     }
 
diff --git a/FitConnect/FluentSender.cs b/FitConnect/FluentSender.cs
index 2867a5bf671fd65232fec799f01f32809eeec577..028ef8fb38f09f39b9baabed637a82c493e2c895 100644
--- a/FitConnect/FluentSender.cs
+++ b/FitConnect/FluentSender.cs
@@ -30,6 +30,7 @@ public class FluentSender : Sender {
     /// <exception cref="InvalidOperationException"></exception>
     /// <exception cref="ArgumentException"></exception>
     public FluentSender CreateSubmission(Submission submission) {
+        this.Submission = submission;
         if (token == null)
             throw new InvalidOperationException("You must authenticate first.");
 
@@ -41,26 +42,36 @@ public class FluentSender : Sender {
         return this;
     }
 
+    public Submission Submission { get; set; }
+
     public FluentSender SendSubmission() {
         throw new NotImplementedException();
     }
 
-    public FluentSender UploadAttachments(List<Attachment> attachments) {
+    public FluentSender UploadAttachments() {
         if (NewSubmission == null)
             throw new InvalidOperationException("You must create a submission first.");
 
-        if (attachments.Count == 0)
+        if (Submission.Attachments.Count == 0)
             return this;
 
-        var encryptedAttachments = Encrypt(PublicKey, attachments);
+        var encryptedAttachments = Encrypt(PublicKey, Submission.Attachments);
         UploadAttachmentsAsync(encryptedAttachments).Wait();
 
         return this;
     }
 
     public FluentSender SendSubmission(Metadata metadata, Data? data = null) {
-        throw new NotImplementedException();
+        if (NewSubmission == null)
+            throw new InvalidOperationException("You must create a submission first.");
+        
+        Submission.Metadata = metadata;
+        Submission.Data = data;
+        var submitSubmissionDto =  CreateSubmitSubmissionDto(Submission);
+        ApiService.SubmissionService.SubmitSubmission(Submission.Id, submitSubmissionDto);
+        return this;
     }
+    
 
     public FluentSender(FitConnectEndpoints endpoints, X509Certificate2? certificate = null,
         ILogger? logger = null) : base(endpoints, certificate, logger) {
diff --git a/FitConnect/Models/FitConnectException.cs b/FitConnect/Models/FitConnectException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70fecf2f3bf2e3888512c0837561e9f98401d5db
--- /dev/null
+++ b/FitConnect/Models/FitConnectException.cs
@@ -0,0 +1,17 @@
+namespace FitConnect.Models;
+
+/// <summary>
+/// Representation of FitConnect error responses
+/// </summary>
+public class FitConnectException : Exception {
+    public enum ErrorTypeEnum {
+        Unknown,
+    }
+
+    public ErrorTypeEnum ErrorType { get; set; }
+
+    public FitConnectException(string message, ErrorTypeEnum errorType = ErrorTypeEnum.Unknown,
+        Exception? innerException = null) : base(message, innerException) {
+        ErrorType = errorType;
+    }
+}
diff --git a/FitConnect/Models/Metadata.cs b/FitConnect/Models/Metadata.cs
index 8caccfe8ed2d4f0decaf77e6b527e09c2c2a8ec7..c9b798a0cc8f1bbcdae795cf166d42bccede59cd 100644
--- a/FitConnect/Models/Metadata.cs
+++ b/FitConnect/Models/Metadata.cs
@@ -1,5 +1,21 @@
+using System.Security.Cryptography.X509Certificates;
+using FitConnect.Models;
+
 namespace FitConnect.Models;
 
-public record Metadata;
+public interface IEncrypt {
+    public string Encrypt(PublicKey publicKey);
+}
+
+public class Metadata : IEncrypt {
+    public string Encrypt(PublicKey publicKey) {
+        return "";
+    }
+}
+
 
-public record Data;
+public class Data : IEncrypt {
+    public string Encrypt(PublicKey publicKey) {
+        return "";
+    }
+}
diff --git a/FitConnect/Models/ServiceType.cs b/FitConnect/Models/ServiceType.cs
index 236a8ceb53a64ecde082ca9499c79a86a3776d02..aee540c41d4e5ab046c98d4f913040843db4c074 100644
--- a/FitConnect/Models/ServiceType.cs
+++ b/FitConnect/Models/ServiceType.cs
@@ -2,7 +2,7 @@ using FitConnect.Services.Models;
 
 namespace FitConnect.Models;
 
-public record ServiceType {
+public class ServiceType {
     public string? Name { get; set; }
 
     public string? Description { get; set; }
@@ -23,4 +23,7 @@ public record ServiceType {
             Name = model.Name
         };
     }
+
+    public bool IsValid() =>
+        (!string.IsNullOrWhiteSpace(Name)) && (!string.IsNullOrWhiteSpace(Identifier));
 }
diff --git a/FitConnect/Models/Submission.cs b/FitConnect/Models/Submission.cs
index e12ed517037f720824acf4940e6ea5a076e848d2..c58dd0492e0ff3fe9482cebea09e5068d487f127 100644
--- a/FitConnect/Models/Submission.cs
+++ b/FitConnect/Models/Submission.cs
@@ -1,9 +1,10 @@
+using System.Security.Cryptography.X509Certificates;
 using FitConnect.Services.Models;
 
 namespace FitConnect.Models;
 
-public record Submission {
-    public string? Id { get; set; }
+public class Submission {
+    public string Id { get; set; }
     public string DestinationId { get; init; }
     public string? CaseId { get; set; }
 
@@ -13,9 +14,22 @@ public record Submission {
 
     public Callback? Callback { get; set; }
 
+
     public bool IsSubmissionReadyToAdd(out string? error) {
-        error = null;
-        return true;
+        var innerError = "";
+        if (string.IsNullOrEmpty(DestinationId)) innerError += "DestinationId is required\r\n";
+
+        if (ServiceType.IsValid()) {
+            innerError += "ServiceType is invalid\r\n";
+        }
+
+        if (string.IsNullOrWhiteSpace(innerError)) {
+            error = null;
+            return true;
+        }
+
+        error = innerError.Trim();
+        return false;
     }
 
     public bool IsSubmissionReadyToSend() {
@@ -26,7 +40,9 @@ public record Submission {
     /// <summary>
     ///     Fachdaten
     /// </summary>
-    public string? Data { get; set; }
+    public Data? Data { get; set; }
+
+    public Metadata Metadata { get; set; }
 
     public static explicit operator Submission(SubmissionForPickupDto dto) {
         return new() {
diff --git a/FitConnect/Sender.cs b/FitConnect/Sender.cs
index c265c97d8305fb05a4c47de4ae8d6a0745cf52be..a074f513981a931067bfba5aa0750beec1cec5cb 100644
--- a/FitConnect/Sender.cs
+++ b/FitConnect/Sender.cs
@@ -7,9 +7,10 @@ using Microsoft.Extensions.Logging;
 namespace FitConnect;
 
 public partial class Sender : FunctionalBaseClass {
+
     public Sender(FitConnectEndpoints endpoints,
-        X509Certificate2? certificate = null, ILogger? logger = null) : base(logger, endpoints,
-        certificate) {
+        X509Certificate2 certificate, ILogger? logger = null) : base(endpoints,
+        certificate, logger) {
     }
 
 
@@ -144,4 +145,11 @@ public partial class Sender : FunctionalBaseClass {
     public async Task<bool> SubmitAsync(string encryptedData, string encryptedMetadata) {
         throw new NotImplementedException();
     }
+
+    protected SubmitSubmissionDto CreateSubmitSubmissionDto(Submission submission) {
+        return new() {
+            EncryptedData = submission.Data?.Encrypt(this.Certificate.PublicKey),
+            EncryptedMetadata = submission.Metadata.Encrypt(Certificate.PublicKey),
+        };
+    }
 }
diff --git a/FitConnect/Subscriber.cs b/FitConnect/Subscriber.cs
index a9a53deba643bc6760240f52e781082a707658d1..846a1bc27a08e9613fda19dfbad40112cc68cc5a 100644
--- a/FitConnect/Subscriber.cs
+++ b/FitConnect/Subscriber.cs
@@ -10,8 +10,8 @@ namespace FitConnect;
 
 public class Subscriber : FunctionalBaseClass {
     public Subscriber(FitConnectEndpoints endpoints,
-        X509Certificate2? certificate = null, ILogger? logger = null) : base(logger, endpoints,
-        certificate) {
+        X509Certificate2 certificate, ILogger? logger = null) : base(endpoints,
+        certificate, logger) {
     }
 
 
@@ -110,4 +110,4 @@ public class Subscriber : FunctionalBaseClass {
         int limit = 100) {
         throw new NotImplementedException();
     }
-}
\ No newline at end of file
+}
diff --git a/Models/Models.csproj b/Models/Models.csproj
index 42326e5c3ec81e82a29317e741d328d2d68ef0b9..245b8c8d902f44288fb973cbc21b2653b5342dcf 100644
--- a/Models/Models.csproj
+++ b/Models/Models.csproj
@@ -7,4 +7,8 @@
         <RootNamespace>FitConnect.Models</RootNamespace>
     </PropertyGroup>
 
+    <ItemGroup>
+      <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
+    </ItemGroup>
+
 </Project>
diff --git a/Services/FitConnectApiService.cs b/Services/FitConnectApiService.cs
index 26cc5d9922b62af28918743bd8b415de101a52f3..4453ddc98e7c869ed371e5859133f2aa726bfaba 100644
--- a/Services/FitConnectApiService.cs
+++ b/Services/FitConnectApiService.cs
@@ -7,7 +7,7 @@ public class FitConnectApiService {
     protected readonly DestinationService DestinationService;
     public readonly OAuthService OAuthService;
     public readonly RouteService RouteService;
-    protected readonly SubmissionService SubmissionService;
+    public readonly SubmissionService SubmissionService;
 
     public FitConnectApiService(FitConnectEndpoints endpoints, ILogger? logger = null) {
         CasesService = new CasesService(endpoints.SubmissionUrl);
diff --git a/Services/Models/Api/Metadata.cs b/Services/Models/Api/Metadata.cs
new file mode 100644
index 0000000000000000000000000000000000000000..adb00423acc5f7729507d4e42e6db8773aa5bd57
--- /dev/null
+++ b/Services/Models/Api/Metadata.cs
@@ -0,0 +1,1122 @@
+// <auto-generated />
+//
+// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
+//
+//    using FitConnect;
+//
+//    var metadata = Metadata.FromJson(jsonString);
+
+namespace FitConnect.Models.Api.Metadata
+{
+    using System;
+    using System.Collections.Generic;
+
+    using System.Globalization;
+    using Newtonsoft.Json;
+    using Newtonsoft.Json.Converters;
+
+    public partial class Metadata
+    {
+        /// <summary>
+        /// Eine Struktur, um zusätzliche Informationen zu hinterlegen
+        /// </summary>
+        [JsonProperty("additionalReferenceInfo", NullValueHandling = NullValueHandling.Ignore)]
+        public AdditionalReferenceInfo AdditionalReferenceInfo { get; set; }
+
+        /// <summary>
+        /// Eine Liste aller Identifikationsnachweise der Einreichung.
+        /// </summary>
+        [JsonProperty("authenticationInformation", NullValueHandling = NullValueHandling.Ignore)]
+        public List<AuthenticationInformation> AuthenticationInformation { get; set; }
+
+        /// <summary>
+        /// Beschreibt die Struktur der zusätzlichen Inhalte der Einreichung, wie Anlagen oder
+        /// Fachdaten.
+        /// </summary>
+        [JsonProperty("contentStructure")]
+        public ContentStructure ContentStructure { get; set; }
+
+        /// <summary>
+        /// Dieses Objekt enthält die Informationen vom Bezahldienst.
+        /// </summary>
+        [JsonProperty("paymentInformation", NullValueHandling = NullValueHandling.Ignore)]
+        public PaymentInformation PaymentInformation { get; set; }
+
+        /// <summary>
+        /// Beschreibung der Art der Verwaltungsleistung. Eine Verwaltungsleistung sollte immer mit
+        /// einer LeiKa-Id beschrieben werden. Ist für die gegebene Verwaltungsleistung keine
+        /// LeiKa-Id vorhanden, kann die Verwaltungsleistung übergangsweise über die Angabe einer
+        /// anderen eindeutigen Schema-URN beschrieben werden.
+        /// </summary>
+        [JsonProperty("publicServiceType", NullValueHandling = NullValueHandling.Ignore)]
+        public Verwaltungsleistung PublicServiceType { get; set; }
+
+        [JsonProperty("replyChannel", NullValueHandling = NullValueHandling.Ignore)]
+        public ReplyChannel ReplyChannel { get; set; }
+    }
+
+    /// <summary>
+    /// Eine Struktur, um zusätzliche Informationen zu hinterlegen
+    /// </summary>
+    public partial class AdditionalReferenceInfo
+    {
+        /// <summary>
+        /// Das Datum der Antragstellung. Das Datum muss nicht zwingend identisch mit dem Datum der
+        /// Einreichung des Antrags über FIT-Connect sein.
+        /// </summary>
+        [JsonProperty("applicationDate", NullValueHandling = NullValueHandling.Ignore)]
+        public DateTimeOffset? ApplicationDate { get; set; }
+
+        /// <summary>
+        /// Eine Referenz zum Vorgang im sendenden System, um bei Problemen und Rückfragen
+        /// außerhalb von FIT-Connect den Vorgang im dortigen System schneller zu identifizieren.
+        /// </summary>
+        [JsonProperty("senderReference", NullValueHandling = NullValueHandling.Ignore)]
+        public string SenderReference { get; set; }
+    }
+
+    /// <summary>
+    /// Eine Struktur, die einen Identifikationsnachweis beschreibt.
+    /// </summary>
+    public partial class AuthenticationInformation
+    {
+        /// <summary>
+        /// Der Nachweis wird als Base64Url-kodierte Zeichenkette angegeben.
+        /// </summary>
+        [JsonProperty("content")]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Definiert die Art des Identifikationsnachweises.
+        /// </summary>
+        [JsonProperty("type")]
+        public AuthenticationInformationType Type { get; set; }
+
+        /// <summary>
+        /// semver kompatible Versionsangabe des genutzten Nachweistyps.
+        /// </summary>
+        [JsonProperty("version")]
+        public string Version { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibt die Struktur der zusätzlichen Inhalte der Einreichung, wie Anlagen oder
+    /// Fachdaten.
+    /// </summary>
+    public partial class ContentStructure
+    {
+        [JsonProperty("attachments")]
+        public List<Attachment> Attachments { get; set; }
+
+        /// <summary>
+        /// Definiert das Schema und die Signatur(-art), die für die Fachdaten verwendet werden.
+        /// </summary>
+        [JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
+        public Data Data { get; set; }
+    }
+
+    /// <summary>
+    /// Eine in der Einreichung enthaltene Anlage.
+    /// </summary>
+    public partial class Attachment
+    {
+        /// <summary>
+        /// Innerhalb einer Einreichung eindeutige Id der Anlage im Format einer UUIDv4.
+        /// </summary>
+        [JsonProperty("attachmentId")]
+        public Guid AttachmentId { get; set; }
+
+        /// <summary>
+        /// Optionale Beschreibung der Anlage
+        /// </summary>
+        [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// Ursprünglicher Dateiname bei Erzeugung oder Upload
+        /// </summary>
+        [JsonProperty("filename", NullValueHandling = NullValueHandling.Ignore)]
+        public string Filename { get; set; }
+
+        /// <summary>
+        /// Der Hashwert der unverschlüsselten Anlage. Die Angabe des Hashwertes dient der
+        /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Anlage durch
+        /// Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+        /// </summary>
+        [JsonProperty("hash")]
+        public AttachmentHash Hash { get; set; }
+
+        /// <summary>
+        /// Internet Media Type gemäß RFC 2045, z. B. application/pdf.
+        /// </summary>
+        [JsonProperty("mimeType")]
+        public string MimeType { get; set; }
+
+        /// <summary>
+        /// Zweck/Art der Anlage
+        /// - form: Automatisch generierte PDF-Repräsentation des vollständigen Antragsformulars
+        /// - attachment: Anlage, die von einem Bürger hochgeladen wurde
+        /// - report: Vom Onlinedienst, nachträglich erzeugte Unterlage
+        /// </summary>
+        [JsonProperty("purpose")]
+        public Purpose Purpose { get; set; }
+
+        [JsonProperty("signature", NullValueHandling = NullValueHandling.Ignore)]
+        public AttachmentSignature Signature { get; set; }
+    }
+
+    /// <summary>
+    /// Der Hashwert der unverschlüsselten Anlage. Die Angabe des Hashwertes dient der
+    /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Anlage durch
+    /// Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+    /// </summary>
+    public partial class AttachmentHash
+    {
+        /// <summary>
+        /// Der Hex-kodierte Hashwert gemäß des angegebenen Algorithmus.
+        /// </summary>
+        [JsonProperty("content")]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Der verwendete Hash-Algorithmus. Derzeit ist nur `sha512` erlaubt.
+        /// </summary>
+        [JsonProperty("type")]
+        public HashType Type { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibt das Signaturformt und Profile
+    /// </summary>
+    public partial class AttachmentSignature
+    {
+        /// <summary>
+        /// Hier wird die Signatur im Falle einer Detached-Signatur als Base64- oder
+        /// Base64Url-kodierte Zeichenkette hinterlegt. Eine Base64Url-Kodierung kommt nur bei
+        /// Einsatz von JSON Web Signatures (JWS / JAdES) zum Einsatz.
+        /// </summary>
+        [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Beschreibt, ob die Signatur als seperate (detached) Signatur (`true`) oder als Teil des
+        /// Fachdatensatzes bzw. der Anlage  (`false`) übertragen wird. Wenn der Wert `true` ist,
+        /// dann wird die Signatur Base64- oder Base64Url-kodiert im Feld `content` übertragen.
+        /// </summary>
+        [JsonProperty("detachedSignature")]
+        public bool DetachedSignature { get; set; }
+
+        /// <summary>
+        /// Referenziert ein eindeutiges Profil einer AdES (advanced electronic signature/seal)
+        /// gemäß eIDAS-Verordnung über eine URI gemäß [ETSI TS 119
+        /// 192](https://www.etsi.org/deliver/etsi_ts/119100_119199/119192/01.01.01_60/ts_119192v010101p.pdf).
+        ///
+        /// Für die Details zur Verwendung und Validierung von Profilen siehe auch
+        /// https://ec.europa.eu/cefdigital/DSS/webapp-demo/doc/dss-documentation.html#_signatures_profile_simplification
+        /// </summary>
+        [JsonProperty("eidasAdesProfile", NullValueHandling = NullValueHandling.Ignore)]
+        public EidasAdesProfile? EidasAdesProfile { get; set; }
+
+        /// <summary>
+        /// Beschreibt, welches Signaturformat die genutzte Signatur / das genutzte Siegel nutzt.
+        /// Aktuell wird die Hinterlegung folgender Signaturformate unterstützt: CMS = Cryptographic
+        /// Message Syntax, Asic = Associated Signature Containers, PDF = PDF Signatur, XML =
+        /// XML-Signature, JSON = JSON Web Signature.
+        /// </summary>
+        [JsonProperty("signatureFormat")]
+        public SignatureFormat SignatureFormat { get; set; }
+    }
+
+    /// <summary>
+    /// Definiert das Schema und die Signatur(-art), die für die Fachdaten verwendet werden.
+    /// </summary>
+    public partial class Data
+    {
+        /// <summary>
+        /// Der Hashwert der unverschlüsselten Fachdaten. Die Angabe des Hashwertes dient der
+        /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Fachdaten
+        /// durch Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+        /// </summary>
+        [JsonProperty("hash")]
+        public DataHash Hash { get; set; }
+
+        /// <summary>
+        /// Beschreibt das Signaturformt und Profile
+        /// </summary>
+        [JsonProperty("signature", NullValueHandling = NullValueHandling.Ignore)]
+        public DataSignature Signature { get; set; }
+
+        /// <summary>
+        /// Referenz auf ein Schema, das die Struktur der Fachdaten einer Einreichung beschreibt.
+        /// </summary>
+        [JsonProperty("submissionSchema")]
+        public Fachdatenschema SubmissionSchema { get; set; }
+    }
+
+    /// <summary>
+    /// Der Hashwert der unverschlüsselten Fachdaten. Die Angabe des Hashwertes dient der
+    /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Fachdaten
+    /// durch Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+    /// </summary>
+    public partial class DataHash
+    {
+        /// <summary>
+        /// Der Hex-kodierte Hashwert gemäß des angegebenen Algorithmus.
+        /// </summary>
+        [JsonProperty("content")]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Der verwendete Hash-Algorithmus. Derzeit ist nur `sha512` erlaubt.
+        /// </summary>
+        [JsonProperty("type")]
+        public HashType Type { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibt das Signaturformt und Profile
+    /// </summary>
+    public partial class DataSignature
+    {
+        /// <summary>
+        /// Hier wird die Signatur im Falle einer Detached-Signatur als Base64- oder
+        /// Base64Url-kodierte Zeichenkette hinterlegt. Eine Base64Url-Kodierung kommt nur bei
+        /// Einsatz von JSON Web Signatures (JWS / JAdES) zum Einsatz.
+        /// </summary>
+        [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Beschreibt, ob die Signatur als seperate (detached) Signatur (`true`) oder als Teil des
+        /// Fachdatensatzes bzw. der Anlage  (`false`) übertragen wird. Wenn der Wert `true` ist,
+        /// dann wird die Signatur Base64- oder Base64Url-kodiert im Feld `content` übertragen.
+        /// </summary>
+        [JsonProperty("detachedSignature")]
+        public bool DetachedSignature { get; set; }
+
+        /// <summary>
+        /// Referenziert ein eindeutiges Profil einer AdES (advanced electronic signature/seal)
+        /// gemäß eIDAS-Verordnung über eine URI gemäß [ETSI TS 119
+        /// 192](https://www.etsi.org/deliver/etsi_ts/119100_119199/119192/01.01.01_60/ts_119192v010101p.pdf).
+        ///
+        /// Für die Details zur Verwendung und Validierung von Profilen siehe auch
+        /// https://ec.europa.eu/cefdigital/DSS/webapp-demo/doc/dss-documentation.html#_signatures_profile_simplification
+        /// </summary>
+        [JsonProperty("eidasAdesProfile", NullValueHandling = NullValueHandling.Ignore)]
+        public EidasAdesProfile? EidasAdesProfile { get; set; }
+
+        /// <summary>
+        /// Beschreibt, welches Signaturformat die genutzte Signatur / das genutzte Siegel nutzt.
+        /// Aktuell wird die Hinterlegung folgender Signaturformate unterstützt: CMS = Cryptographic
+        /// Message Syntax, Asic = Associated Signature Containers, PDF = PDF Signatur, XML =
+        /// XML-Signature, JSON = JSON Web Signature.
+        /// </summary>
+        [JsonProperty("signatureFormat")]
+        public SignatureFormat SignatureFormat { get; set; }
+    }
+
+    /// <summary>
+    /// Referenz auf ein Schema, das die Struktur der Fachdaten einer Einreichung beschreibt.
+    /// </summary>
+    public partial class Fachdatenschema
+    {
+        /// <summary>
+        /// Mimetype (z.B. application/json oder application/xml) des referenzierten Schemas (z.B.
+        /// XSD- oder JSON-Schema).
+        /// </summary>
+        [JsonProperty("mimeType")]
+        public MimeType MimeType { get; set; }
+
+        /// <summary>
+        /// URI des Fachschemas. Wird hier eine URL verwendet, sollte das Schema unter der
+        /// angegebenen URL abrufbar sein. Eine Verfügbarkeit des Schemas unter der angegebenen URL
+        /// darf jedoch nicht vorausgesetzt werden.
+        /// </summary>
+        [JsonProperty("schemaUri")]
+        public Uri SchemaUri { get; set; }
+    }
+
+    /// <summary>
+    /// Dieses Objekt enthält die Informationen vom Bezahldienst.
+    /// </summary>
+    public partial class PaymentInformation
+    {
+        /// <summary>
+        /// Bruttobetrag
+        /// </summary>
+        [JsonProperty("grossAmount", NullValueHandling = NullValueHandling.Ignore)]
+        [JsonConverter(typeof(MinMaxValueCheckConverter))]
+        public double? GrossAmount { get; set; }
+
+        /// <summary>
+        /// Die vom Benutzer ausgewählte Zahlart. Das Feld ist nur bei einer erfolgreichen Zahlung
+        /// vorhanden / befüllt.
+        /// </summary>
+        [JsonProperty("paymentMethod")]
+        public PaymentMethod PaymentMethod { get; set; }
+
+        /// <summary>
+        /// Weitere Erläuterung zur gewählten Zahlart.
+        /// </summary>
+        [JsonProperty("paymentMethodDetail", NullValueHandling = NullValueHandling.Ignore)]
+        [JsonConverter(typeof(PurpleMinMaxLengthCheckConverter))]
+        public string PaymentMethodDetail { get; set; }
+
+        /// <summary>
+        /// - INITIAL - der Einreichung hat einen Payment-Request ausgelöst und eine
+        /// Payment-Transaction wurde angelegt. Der Nutzer hat aber im Bezahldienst noch keine
+        /// Wirkung erzeugt.
+        /// - BOOKED - der Nutzer hat die Bezahlung im Bezahldienst autorisiert.
+        /// - FAILED - der Vorgang wurde vom Bezahldienst aufgrund der Nutzereingaben abgebrochen.
+        /// - CANCELED - der Nutzer hat die Bezahlung im Bezahldienst abgebrochen.
+        /// </summary>
+        [JsonProperty("status")]
+        public Status Status { get; set; }
+
+        /// <summary>
+        /// Eine vom Bezahldienst vergebene Transaktions-Id.
+        /// </summary>
+        [JsonProperty("transactionId")]
+        [JsonConverter(typeof(PurpleMinMaxLengthCheckConverter))]
+        public string TransactionId { get; set; }
+
+        /// <summary>
+        /// Bezahlreferenz bzw. Verwendungszweck, wie z. B. ein Kassenzeichen.
+        /// </summary>
+        [JsonProperty("transactionReference")]
+        public string TransactionReference { get; set; }
+
+        /// <summary>
+        /// Zeitstempel der erfolgreichen Durchführung der Bezahlung.
+        /// </summary>
+        [JsonProperty("transactionTimestamp", NullValueHandling = NullValueHandling.Ignore)]
+        public DateTimeOffset? TransactionTimestamp { get; set; }
+
+        /// <summary>
+        /// Die Rest-URL der Payment Transaction für die Statusabfrage.
+        /// </summary>
+        [JsonProperty("transactionUrl", NullValueHandling = NullValueHandling.Ignore)]
+        public Uri TransactionUrl { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibung der Art der Verwaltungsleistung. Eine Verwaltungsleistung sollte immer mit
+    /// einer LeiKa-Id beschrieben werden. Ist für die gegebene Verwaltungsleistung keine
+    /// LeiKa-Id vorhanden, kann die Verwaltungsleistung übergangsweise über die Angabe einer
+    /// anderen eindeutigen Schema-URN beschrieben werden.
+    /// </summary>
+    public partial class Verwaltungsleistung
+    {
+        /// <summary>
+        /// (Kurz-)Beschreibung der Verwaltungsleistung
+        /// </summary>
+        [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// URN einer Leistung. Im Falle einer Leistung aus dem Leistungskatalog sollte hier
+        /// `urn:de:fim:leika:leistung:` vorangestellt werden.
+        /// </summary>
+        [JsonProperty("identifier")]
+        [JsonConverter(typeof(FluffyMinMaxLengthCheckConverter))]
+        public string Identifier { get; set; }
+
+        /// <summary>
+        /// Name/Bezeichnung der Verwaltungsleistung
+        /// </summary>
+        [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
+        public string Name { get; set; }
+    }
+
+    public partial class ReplyChannel
+    {
+        /// <summary>
+        /// Akkreditierte Anbieter siehe
+        /// https://www.bsi.bund.de/DE/Themen/Oeffentliche-Verwaltung/Moderner-Staat/De-Mail/Akkreditierte-DMDA/akkreditierte-dmda_node.html
+        /// </summary>
+        [JsonProperty("deMail", NullValueHandling = NullValueHandling.Ignore)]
+        public DeMail DeMail { get; set; }
+
+        /// <summary>
+        /// Siehe https://www.elster.de/elsterweb/infoseite/elstertransfer_hilfe_schnittstellen
+        /// </summary>
+        [JsonProperty("elster", NullValueHandling = NullValueHandling.Ignore)]
+        public Elster Elster { get; set; }
+
+        [JsonProperty("eMail", NullValueHandling = NullValueHandling.Ignore)]
+        public EMail EMail { get; set; }
+
+        /// <summary>
+        /// Postfachadresse in einem interoperablen Servicekonto (FINK.PFISK)
+        /// </summary>
+        [JsonProperty("fink", NullValueHandling = NullValueHandling.Ignore)]
+        public Fink Fink { get; set; }
+    }
+
+    /// <summary>
+    /// Akkreditierte Anbieter siehe
+    /// https://www.bsi.bund.de/DE/Themen/Oeffentliche-Verwaltung/Moderner-Staat/De-Mail/Akkreditierte-DMDA/akkreditierte-dmda_node.html
+    /// </summary>
+    public partial class DeMail
+    {
+        [JsonProperty("address")]
+        public string Address { get; set; }
+    }
+
+    public partial class EMail
+    {
+        [JsonProperty("address")]
+        public string Address { get; set; }
+
+        /// <summary>
+        /// Hilfe zur Erstellung gibt es in der Dokumentation unter
+        /// https://docs.fitko.de/fit-connect/details/pgp-export
+        /// </summary>
+        [JsonProperty("pgpPublicKey", NullValueHandling = NullValueHandling.Ignore)]
+        public string PgpPublicKey { get; set; }
+    }
+
+    /// <summary>
+    /// Siehe https://www.elster.de/elsterweb/infoseite/elstertransfer_hilfe_schnittstellen
+    /// </summary>
+    public partial class Elster
+    {
+        [JsonProperty("accountId")]
+        public string AccountId { get; set; }
+
+        [JsonProperty("geschaeftszeichen", NullValueHandling = NullValueHandling.Ignore)]
+        [JsonConverter(typeof(TentacledMinMaxLengthCheckConverter))]
+        public string Geschaeftszeichen { get; set; }
+
+        [JsonProperty("lieferTicket", NullValueHandling = NullValueHandling.Ignore)]
+        public string LieferTicket { get; set; }
+    }
+
+    /// <summary>
+    /// Postfachadresse in einem interoperablen Servicekonto (FINK.PFISK)
+    /// </summary>
+    public partial class Fink
+    {
+        /// <summary>
+        /// FINK Postfachadresse
+        /// </summary>
+        [JsonProperty("finkPostfachRef")]
+        [JsonConverter(typeof(StickyMinMaxLengthCheckConverter))]
+        public string FinkPostfachRef { get; set; }
+
+        /// <summary>
+        /// URL des Servicekontos, in dem das Ziel-Postfach liegt
+        /// </summary>
+        [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)]
+        public Uri Host { get; set; }
+    }
+
+    /// <summary>
+    /// Definiert die Art des Identifikationsnachweises.
+    /// </summary>
+    public enum AuthenticationInformationType { IdentificationReport };
+
+    /// <summary>
+    /// Der verwendete Hash-Algorithmus. Derzeit ist nur `sha512` erlaubt.
+    /// </summary>
+    public enum HashType { Sha512 };
+
+    /// <summary>
+    /// Zweck/Art der Anlage
+    /// - form: Automatisch generierte PDF-Repräsentation des vollständigen Antragsformulars
+    /// - attachment: Anlage, die von einem Bürger hochgeladen wurde
+    /// - report: Vom Onlinedienst, nachträglich erzeugte Unterlage
+    /// </summary>
+    public enum Purpose { Attachment, Form, Report };
+
+    /// <summary>
+    /// Referenziert ein eindeutiges Profil einer AdES (advanced electronic signature/seal)
+    /// gemäß eIDAS-Verordnung über eine URI gemäß [ETSI TS 119
+    /// 192](https://www.etsi.org/deliver/etsi_ts/119100_119199/119192/01.01.01_60/ts_119192v010101p.pdf).
+    ///
+    /// Für die Details zur Verwendung und Validierung von Profilen siehe auch
+    /// https://ec.europa.eu/cefdigital/DSS/webapp-demo/doc/dss-documentation.html#_signatures_profile_simplification
+    /// </summary>
+    public enum EidasAdesProfile { HttpUriEtsiOrgAdes191X2LevelBaselineBB, HttpUriEtsiOrgAdes191X2LevelBaselineBLt, HttpUriEtsiOrgAdes191X2LevelBaselineBLta, HttpUriEtsiOrgAdes191X2LevelBaselineBT };
+
+    /// <summary>
+    /// Beschreibt, welches Signaturformat die genutzte Signatur / das genutzte Siegel nutzt.
+    /// Aktuell wird die Hinterlegung folgender Signaturformate unterstützt: CMS = Cryptographic
+    /// Message Syntax, Asic = Associated Signature Containers, PDF = PDF Signatur, XML =
+    /// XML-Signature, JSON = JSON Web Signature.
+    /// </summary>
+    public enum SignatureFormat { Asic, Cms, Json, Pdf, Xml };
+
+    /// <summary>
+    /// Mimetype (z.B. application/json oder application/xml) des referenzierten Schemas (z.B.
+    /// XSD- oder JSON-Schema).
+    /// </summary>
+    public enum MimeType { ApplicationJson, ApplicationXml };
+
+    /// <summary>
+    /// Die vom Benutzer ausgewählte Zahlart. Das Feld ist nur bei einer erfolgreichen Zahlung
+    /// vorhanden / befüllt.
+    /// </summary>
+    public enum PaymentMethod { Creditcard, Giropay, Invoice, Other, Paydirect, Paypal };
+
+    /// <summary>
+    /// - INITIAL - der Einreichung hat einen Payment-Request ausgelöst und eine
+    /// Payment-Transaction wurde angelegt. Der Nutzer hat aber im Bezahldienst noch keine
+    /// Wirkung erzeugt.
+    /// - BOOKED - der Nutzer hat die Bezahlung im Bezahldienst autorisiert.
+    /// - FAILED - der Vorgang wurde vom Bezahldienst aufgrund der Nutzereingaben abgebrochen.
+    /// - CANCELED - der Nutzer hat die Bezahlung im Bezahldienst abgebrochen.
+    /// </summary>
+    public enum Status { Booked, Canceled, Failed, Initial };
+
+    public partial class Metadata
+    {
+        public static Metadata FromJson(string json) => JsonConvert.DeserializeObject<Metadata>(json, FitConnect.Models.Api.Metadata.Converter.Settings);
+    }
+
+    public static class Serialize
+    {
+        public static string ToJson(this Metadata self) => JsonConvert.SerializeObject(self, FitConnect.Models.Api.Metadata.Converter.Settings);
+    }
+
+    internal static class Converter
+    {
+        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
+        {
+            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
+            DateParseHandling = DateParseHandling.None,
+            Converters =
+            {
+                AuthenticationInformationTypeConverter.Singleton,
+                HashTypeConverter.Singleton,
+                PurposeConverter.Singleton,
+                EidasAdesProfileConverter.Singleton,
+                SignatureFormatConverter.Singleton,
+                MimeTypeConverter.Singleton,
+                PaymentMethodConverter.Singleton,
+                StatusConverter.Singleton,
+                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
+            },
+        };
+    }
+
+    internal class AuthenticationInformationTypeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(AuthenticationInformationType) || t == typeof(AuthenticationInformationType?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            if (value == "identificationReport")
+            {
+                return AuthenticationInformationType.IdentificationReport;
+            }
+            throw new Exception("Cannot unmarshal type AuthenticationInformationType");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (AuthenticationInformationType)untypedValue;
+            if (value == AuthenticationInformationType.IdentificationReport)
+            {
+                serializer.Serialize(writer, "identificationReport");
+                return;
+            }
+            throw new Exception("Cannot marshal type AuthenticationInformationType");
+        }
+
+        public static readonly AuthenticationInformationTypeConverter Singleton = new AuthenticationInformationTypeConverter();
+    }
+
+    internal class HashTypeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(HashType) || t == typeof(HashType?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            if (value == "sha512")
+            {
+                return HashType.Sha512;
+            }
+            throw new Exception("Cannot unmarshal type HashType");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (HashType)untypedValue;
+            if (value == HashType.Sha512)
+            {
+                serializer.Serialize(writer, "sha512");
+                return;
+            }
+            throw new Exception("Cannot marshal type HashType");
+        }
+
+        public static readonly HashTypeConverter Singleton = new HashTypeConverter();
+    }
+
+    internal class PurposeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(Purpose) || t == typeof(Purpose?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "attachment":
+                    return Purpose.Attachment;
+                case "form":
+                    return Purpose.Form;
+                case "report":
+                    return Purpose.Report;
+            }
+            throw new Exception("Cannot unmarshal type Purpose");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (Purpose)untypedValue;
+            switch (value)
+            {
+                case Purpose.Attachment:
+                    serializer.Serialize(writer, "attachment");
+                    return;
+                case Purpose.Form:
+                    serializer.Serialize(writer, "form");
+                    return;
+                case Purpose.Report:
+                    serializer.Serialize(writer, "report");
+                    return;
+            }
+            throw new Exception("Cannot marshal type Purpose");
+        }
+
+        public static readonly PurposeConverter Singleton = new PurposeConverter();
+    }
+
+    internal class EidasAdesProfileConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(EidasAdesProfile) || t == typeof(EidasAdesProfile?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-B#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBB;
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-LT#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLt;
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-LTA#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLta;
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-T#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBT;
+            }
+            throw new Exception("Cannot unmarshal type EidasAdesProfile");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (EidasAdesProfile)untypedValue;
+            switch (value)
+            {
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBB:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-B#");
+                    return;
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLt:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-LT#");
+                    return;
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLta:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-LTA#");
+                    return;
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBT:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-T#");
+                    return;
+            }
+            throw new Exception("Cannot marshal type EidasAdesProfile");
+        }
+
+        public static readonly EidasAdesProfileConverter Singleton = new EidasAdesProfileConverter();
+    }
+
+    internal class SignatureFormatConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(SignatureFormat) || t == typeof(SignatureFormat?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "asic":
+                    return SignatureFormat.Asic;
+                case "cms":
+                    return SignatureFormat.Cms;
+                case "json":
+                    return SignatureFormat.Json;
+                case "pdf":
+                    return SignatureFormat.Pdf;
+                case "xml":
+                    return SignatureFormat.Xml;
+            }
+            throw new Exception("Cannot unmarshal type SignatureFormat");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (SignatureFormat)untypedValue;
+            switch (value)
+            {
+                case SignatureFormat.Asic:
+                    serializer.Serialize(writer, "asic");
+                    return;
+                case SignatureFormat.Cms:
+                    serializer.Serialize(writer, "cms");
+                    return;
+                case SignatureFormat.Json:
+                    serializer.Serialize(writer, "json");
+                    return;
+                case SignatureFormat.Pdf:
+                    serializer.Serialize(writer, "pdf");
+                    return;
+                case SignatureFormat.Xml:
+                    serializer.Serialize(writer, "xml");
+                    return;
+            }
+            throw new Exception("Cannot marshal type SignatureFormat");
+        }
+
+        public static readonly SignatureFormatConverter Singleton = new SignatureFormatConverter();
+    }
+
+    internal class MimeTypeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(MimeType) || t == typeof(MimeType?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "application/json":
+                    return MimeType.ApplicationJson;
+                case "application/xml":
+                    return MimeType.ApplicationXml;
+            }
+            throw new Exception("Cannot unmarshal type MimeType");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (MimeType)untypedValue;
+            switch (value)
+            {
+                case MimeType.ApplicationJson:
+                    serializer.Serialize(writer, "application/json");
+                    return;
+                case MimeType.ApplicationXml:
+                    serializer.Serialize(writer, "application/xml");
+                    return;
+            }
+            throw new Exception("Cannot marshal type MimeType");
+        }
+
+        public static readonly MimeTypeConverter Singleton = new MimeTypeConverter();
+    }
+
+    internal class MinMaxValueCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(double) || t == typeof(double?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<double>(reader);
+            if (value >= 0.01)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type double");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (double)untypedValue;
+            if (value >= 0.01)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type double");
+        }
+
+        public static readonly MinMaxValueCheckConverter Singleton = new MinMaxValueCheckConverter();
+    }
+
+    internal class PaymentMethodConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(PaymentMethod) || t == typeof(PaymentMethod?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "CREDITCARD":
+                    return PaymentMethod.Creditcard;
+                case "GIROPAY":
+                    return PaymentMethod.Giropay;
+                case "INVOICE":
+                    return PaymentMethod.Invoice;
+                case "OTHER":
+                    return PaymentMethod.Other;
+                case "PAYDIRECT":
+                    return PaymentMethod.Paydirect;
+                case "PAYPAL":
+                    return PaymentMethod.Paypal;
+            }
+            throw new Exception("Cannot unmarshal type PaymentMethod");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (PaymentMethod)untypedValue;
+            switch (value)
+            {
+                case PaymentMethod.Creditcard:
+                    serializer.Serialize(writer, "CREDITCARD");
+                    return;
+                case PaymentMethod.Giropay:
+                    serializer.Serialize(writer, "GIROPAY");
+                    return;
+                case PaymentMethod.Invoice:
+                    serializer.Serialize(writer, "INVOICE");
+                    return;
+                case PaymentMethod.Other:
+                    serializer.Serialize(writer, "OTHER");
+                    return;
+                case PaymentMethod.Paydirect:
+                    serializer.Serialize(writer, "PAYDIRECT");
+                    return;
+                case PaymentMethod.Paypal:
+                    serializer.Serialize(writer, "PAYPAL");
+                    return;
+            }
+            throw new Exception("Cannot marshal type PaymentMethod");
+        }
+
+        public static readonly PaymentMethodConverter Singleton = new PaymentMethodConverter();
+    }
+
+    internal class PurpleMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length >= 1 && value.Length <= 36)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length >= 1 && value.Length <= 36)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly PurpleMinMaxLengthCheckConverter Singleton = new PurpleMinMaxLengthCheckConverter();
+    }
+
+    internal class StatusConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(Status) || t == typeof(Status?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "BOOKED":
+                    return Status.Booked;
+                case "CANCELED":
+                    return Status.Canceled;
+                case "FAILED":
+                    return Status.Failed;
+                case "INITIAL":
+                    return Status.Initial;
+            }
+            throw new Exception("Cannot unmarshal type Status");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (Status)untypedValue;
+            switch (value)
+            {
+                case Status.Booked:
+                    serializer.Serialize(writer, "BOOKED");
+                    return;
+                case Status.Canceled:
+                    serializer.Serialize(writer, "CANCELED");
+                    return;
+                case Status.Failed:
+                    serializer.Serialize(writer, "FAILED");
+                    return;
+                case Status.Initial:
+                    serializer.Serialize(writer, "INITIAL");
+                    return;
+            }
+            throw new Exception("Cannot marshal type Status");
+        }
+
+        public static readonly StatusConverter Singleton = new StatusConverter();
+    }
+
+    internal class FluffyMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length >= 7 && value.Length <= 255)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length >= 7 && value.Length <= 255)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly FluffyMinMaxLengthCheckConverter Singleton = new FluffyMinMaxLengthCheckConverter();
+    }
+
+    internal class TentacledMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length <= 10)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length <= 10)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly TentacledMinMaxLengthCheckConverter Singleton = new TentacledMinMaxLengthCheckConverter();
+    }
+
+    internal class StickyMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length <= 150)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length <= 150)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly StickyMinMaxLengthCheckConverter Singleton = new StickyMinMaxLengthCheckConverter();
+    }
+}
diff --git a/Services/Models/Api/SecurityEventToken.cs b/Services/Models/Api/SecurityEventToken.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fccc4762f5ab79409b498649117f7fc057fd6979
--- /dev/null
+++ b/Services/Models/Api/SecurityEventToken.cs
@@ -0,0 +1,1122 @@
+// <auto-generated />
+//
+// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
+//
+//    using FitConnect;
+//
+//    var metadata = Metadata.FromJson(jsonString);
+
+namespace FitConnect.Models.Api.Set
+{
+    using System;
+    using System.Collections.Generic;
+
+    using System.Globalization;
+    using Newtonsoft.Json;
+    using Newtonsoft.Json.Converters;
+
+    public partial class Metadata
+    {
+        /// <summary>
+        /// Eine Struktur, um zusätzliche Informationen zu hinterlegen
+        /// </summary>
+        [JsonProperty("additionalReferenceInfo", NullValueHandling = NullValueHandling.Ignore)]
+        public AdditionalReferenceInfo AdditionalReferenceInfo { get; set; }
+
+        /// <summary>
+        /// Eine Liste aller Identifikationsnachweise der Einreichung.
+        /// </summary>
+        [JsonProperty("authenticationInformation", NullValueHandling = NullValueHandling.Ignore)]
+        public List<AuthenticationInformation> AuthenticationInformation { get; set; }
+
+        /// <summary>
+        /// Beschreibt die Struktur der zusätzlichen Inhalte der Einreichung, wie Anlagen oder
+        /// Fachdaten.
+        /// </summary>
+        [JsonProperty("contentStructure")]
+        public ContentStructure ContentStructure { get; set; }
+
+        /// <summary>
+        /// Dieses Objekt enthält die Informationen vom Bezahldienst.
+        /// </summary>
+        [JsonProperty("paymentInformation", NullValueHandling = NullValueHandling.Ignore)]
+        public PaymentInformation PaymentInformation { get; set; }
+
+        /// <summary>
+        /// Beschreibung der Art der Verwaltungsleistung. Eine Verwaltungsleistung sollte immer mit
+        /// einer LeiKa-Id beschrieben werden. Ist für die gegebene Verwaltungsleistung keine
+        /// LeiKa-Id vorhanden, kann die Verwaltungsleistung übergangsweise über die Angabe einer
+        /// anderen eindeutigen Schema-URN beschrieben werden.
+        /// </summary>
+        [JsonProperty("publicServiceType", NullValueHandling = NullValueHandling.Ignore)]
+        public Verwaltungsleistung PublicServiceType { get; set; }
+
+        [JsonProperty("replyChannel", NullValueHandling = NullValueHandling.Ignore)]
+        public ReplyChannel ReplyChannel { get; set; }
+    }
+
+    /// <summary>
+    /// Eine Struktur, um zusätzliche Informationen zu hinterlegen
+    /// </summary>
+    public partial class AdditionalReferenceInfo
+    {
+        /// <summary>
+        /// Das Datum der Antragstellung. Das Datum muss nicht zwingend identisch mit dem Datum der
+        /// Einreichung des Antrags über FIT-Connect sein.
+        /// </summary>
+        [JsonProperty("applicationDate", NullValueHandling = NullValueHandling.Ignore)]
+        public DateTimeOffset? ApplicationDate { get; set; }
+
+        /// <summary>
+        /// Eine Referenz zum Vorgang im sendenden System, um bei Problemen und Rückfragen
+        /// außerhalb von FIT-Connect den Vorgang im dortigen System schneller zu identifizieren.
+        /// </summary>
+        [JsonProperty("senderReference", NullValueHandling = NullValueHandling.Ignore)]
+        public string SenderReference { get; set; }
+    }
+
+    /// <summary>
+    /// Eine Struktur, die einen Identifikationsnachweis beschreibt.
+    /// </summary>
+    public partial class AuthenticationInformation
+    {
+        /// <summary>
+        /// Der Nachweis wird als Base64Url-kodierte Zeichenkette angegeben.
+        /// </summary>
+        [JsonProperty("content")]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Definiert die Art des Identifikationsnachweises.
+        /// </summary>
+        [JsonProperty("type")]
+        public AuthenticationInformationType Type { get; set; }
+
+        /// <summary>
+        /// semver kompatible Versionsangabe des genutzten Nachweistyps.
+        /// </summary>
+        [JsonProperty("version")]
+        public string Version { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibt die Struktur der zusätzlichen Inhalte der Einreichung, wie Anlagen oder
+    /// Fachdaten.
+    /// </summary>
+    public partial class ContentStructure
+    {
+        [JsonProperty("attachments")]
+        public List<Attachment> Attachments { get; set; }
+
+        /// <summary>
+        /// Definiert das Schema und die Signatur(-art), die für die Fachdaten verwendet werden.
+        /// </summary>
+        [JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
+        public Data Data { get; set; }
+    }
+
+    /// <summary>
+    /// Eine in der Einreichung enthaltene Anlage.
+    /// </summary>
+    public partial class Attachment
+    {
+        /// <summary>
+        /// Innerhalb einer Einreichung eindeutige Id der Anlage im Format einer UUIDv4.
+        /// </summary>
+        [JsonProperty("attachmentId")]
+        public Guid AttachmentId { get; set; }
+
+        /// <summary>
+        /// Optionale Beschreibung der Anlage
+        /// </summary>
+        [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// Ursprünglicher Dateiname bei Erzeugung oder Upload
+        /// </summary>
+        [JsonProperty("filename", NullValueHandling = NullValueHandling.Ignore)]
+        public string Filename { get; set; }
+
+        /// <summary>
+        /// Der Hashwert der unverschlüsselten Anlage. Die Angabe des Hashwertes dient der
+        /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Anlage durch
+        /// Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+        /// </summary>
+        [JsonProperty("hash")]
+        public AttachmentHash Hash { get; set; }
+
+        /// <summary>
+        /// Internet Media Type gemäß RFC 2045, z. B. application/pdf.
+        /// </summary>
+        [JsonProperty("mimeType")]
+        public string MimeType { get; set; }
+
+        /// <summary>
+        /// Zweck/Art der Anlage
+        /// - form: Automatisch generierte PDF-Repräsentation des vollständigen Antragsformulars
+        /// - attachment: Anlage, die von einem Bürger hochgeladen wurde
+        /// - report: Vom Onlinedienst, nachträglich erzeugte Unterlage
+        /// </summary>
+        [JsonProperty("purpose")]
+        public Purpose Purpose { get; set; }
+
+        [JsonProperty("signature", NullValueHandling = NullValueHandling.Ignore)]
+        public AttachmentSignature Signature { get; set; }
+    }
+
+    /// <summary>
+    /// Der Hashwert der unverschlüsselten Anlage. Die Angabe des Hashwertes dient der
+    /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Anlage durch
+    /// Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+    /// </summary>
+    public partial class AttachmentHash
+    {
+        /// <summary>
+        /// Der Hex-kodierte Hashwert gemäß des angegebenen Algorithmus.
+        /// </summary>
+        [JsonProperty("content")]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Der verwendete Hash-Algorithmus. Derzeit ist nur `sha512` erlaubt.
+        /// </summary>
+        [JsonProperty("type")]
+        public HashType Type { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibt das Signaturformt und Profile
+    /// </summary>
+    public partial class AttachmentSignature
+    {
+        /// <summary>
+        /// Hier wird die Signatur im Falle einer Detached-Signatur als Base64- oder
+        /// Base64Url-kodierte Zeichenkette hinterlegt. Eine Base64Url-Kodierung kommt nur bei
+        /// Einsatz von JSON Web Signatures (JWS / JAdES) zum Einsatz.
+        /// </summary>
+        [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Beschreibt, ob die Signatur als seperate (detached) Signatur (`true`) oder als Teil des
+        /// Fachdatensatzes bzw. der Anlage  (`false`) übertragen wird. Wenn der Wert `true` ist,
+        /// dann wird die Signatur Base64- oder Base64Url-kodiert im Feld `content` übertragen.
+        /// </summary>
+        [JsonProperty("detachedSignature")]
+        public bool DetachedSignature { get; set; }
+
+        /// <summary>
+        /// Referenziert ein eindeutiges Profil einer AdES (advanced electronic signature/seal)
+        /// gemäß eIDAS-Verordnung über eine URI gemäß [ETSI TS 119
+        /// 192](https://www.etsi.org/deliver/etsi_ts/119100_119199/119192/01.01.01_60/ts_119192v010101p.pdf).
+        ///
+        /// Für die Details zur Verwendung und Validierung von Profilen siehe auch
+        /// https://ec.europa.eu/cefdigital/DSS/webapp-demo/doc/dss-documentation.html#_signatures_profile_simplification
+        /// </summary>
+        [JsonProperty("eidasAdesProfile", NullValueHandling = NullValueHandling.Ignore)]
+        public EidasAdesProfile? EidasAdesProfile { get; set; }
+
+        /// <summary>
+        /// Beschreibt, welches Signaturformat die genutzte Signatur / das genutzte Siegel nutzt.
+        /// Aktuell wird die Hinterlegung folgender Signaturformate unterstützt: CMS = Cryptographic
+        /// Message Syntax, Asic = Associated Signature Containers, PDF = PDF Signatur, XML =
+        /// XML-Signature, JSON = JSON Web Signature.
+        /// </summary>
+        [JsonProperty("signatureFormat")]
+        public SignatureFormat SignatureFormat { get; set; }
+    }
+
+    /// <summary>
+    /// Definiert das Schema und die Signatur(-art), die für die Fachdaten verwendet werden.
+    /// </summary>
+    public partial class Data
+    {
+        /// <summary>
+        /// Der Hashwert der unverschlüsselten Fachdaten. Die Angabe des Hashwertes dient der
+        /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Fachdaten
+        /// durch Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+        /// </summary>
+        [JsonProperty("hash")]
+        public DataHash Hash { get; set; }
+
+        /// <summary>
+        /// Beschreibt das Signaturformt und Profile
+        /// </summary>
+        [JsonProperty("signature", NullValueHandling = NullValueHandling.Ignore)]
+        public DataSignature Signature { get; set; }
+
+        /// <summary>
+        /// Referenz auf ein Schema, das die Struktur der Fachdaten einer Einreichung beschreibt.
+        /// </summary>
+        [JsonProperty("submissionSchema")]
+        public Fachdatenschema SubmissionSchema { get; set; }
+    }
+
+    /// <summary>
+    /// Der Hashwert der unverschlüsselten Fachdaten. Die Angabe des Hashwertes dient der
+    /// Integritätssicherung des Gesamtantrags und schützt vor einem Austausch der Fachdaten
+    /// durch Systeme zwischen Sender und Subscriber (z.B. dem Zustelldienst).
+    /// </summary>
+    public partial class DataHash
+    {
+        /// <summary>
+        /// Der Hex-kodierte Hashwert gemäß des angegebenen Algorithmus.
+        /// </summary>
+        [JsonProperty("content")]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Der verwendete Hash-Algorithmus. Derzeit ist nur `sha512` erlaubt.
+        /// </summary>
+        [JsonProperty("type")]
+        public HashType Type { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibt das Signaturformt und Profile
+    /// </summary>
+    public partial class DataSignature
+    {
+        /// <summary>
+        /// Hier wird die Signatur im Falle einer Detached-Signatur als Base64- oder
+        /// Base64Url-kodierte Zeichenkette hinterlegt. Eine Base64Url-Kodierung kommt nur bei
+        /// Einsatz von JSON Web Signatures (JWS / JAdES) zum Einsatz.
+        /// </summary>
+        [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Beschreibt, ob die Signatur als seperate (detached) Signatur (`true`) oder als Teil des
+        /// Fachdatensatzes bzw. der Anlage  (`false`) übertragen wird. Wenn der Wert `true` ist,
+        /// dann wird die Signatur Base64- oder Base64Url-kodiert im Feld `content` übertragen.
+        /// </summary>
+        [JsonProperty("detachedSignature")]
+        public bool DetachedSignature { get; set; }
+
+        /// <summary>
+        /// Referenziert ein eindeutiges Profil einer AdES (advanced electronic signature/seal)
+        /// gemäß eIDAS-Verordnung über eine URI gemäß [ETSI TS 119
+        /// 192](https://www.etsi.org/deliver/etsi_ts/119100_119199/119192/01.01.01_60/ts_119192v010101p.pdf).
+        ///
+        /// Für die Details zur Verwendung und Validierung von Profilen siehe auch
+        /// https://ec.europa.eu/cefdigital/DSS/webapp-demo/doc/dss-documentation.html#_signatures_profile_simplification
+        /// </summary>
+        [JsonProperty("eidasAdesProfile", NullValueHandling = NullValueHandling.Ignore)]
+        public EidasAdesProfile? EidasAdesProfile { get; set; }
+
+        /// <summary>
+        /// Beschreibt, welches Signaturformat die genutzte Signatur / das genutzte Siegel nutzt.
+        /// Aktuell wird die Hinterlegung folgender Signaturformate unterstützt: CMS = Cryptographic
+        /// Message Syntax, Asic = Associated Signature Containers, PDF = PDF Signatur, XML =
+        /// XML-Signature, JSON = JSON Web Signature.
+        /// </summary>
+        [JsonProperty("signatureFormat")]
+        public SignatureFormat SignatureFormat { get; set; }
+    }
+
+    /// <summary>
+    /// Referenz auf ein Schema, das die Struktur der Fachdaten einer Einreichung beschreibt.
+    /// </summary>
+    public partial class Fachdatenschema
+    {
+        /// <summary>
+        /// Mimetype (z.B. application/json oder application/xml) des referenzierten Schemas (z.B.
+        /// XSD- oder JSON-Schema).
+        /// </summary>
+        [JsonProperty("mimeType")]
+        public MimeType MimeType { get; set; }
+
+        /// <summary>
+        /// URI des Fachschemas. Wird hier eine URL verwendet, sollte das Schema unter der
+        /// angegebenen URL abrufbar sein. Eine Verfügbarkeit des Schemas unter der angegebenen URL
+        /// darf jedoch nicht vorausgesetzt werden.
+        /// </summary>
+        [JsonProperty("schemaUri")]
+        public Uri SchemaUri { get; set; }
+    }
+
+    /// <summary>
+    /// Dieses Objekt enthält die Informationen vom Bezahldienst.
+    /// </summary>
+    public partial class PaymentInformation
+    {
+        /// <summary>
+        /// Bruttobetrag
+        /// </summary>
+        [JsonProperty("grossAmount", NullValueHandling = NullValueHandling.Ignore)]
+        [JsonConverter(typeof(MinMaxValueCheckConverter))]
+        public double? GrossAmount { get; set; }
+
+        /// <summary>
+        /// Die vom Benutzer ausgewählte Zahlart. Das Feld ist nur bei einer erfolgreichen Zahlung
+        /// vorhanden / befüllt.
+        /// </summary>
+        [JsonProperty("paymentMethod")]
+        public PaymentMethod PaymentMethod { get; set; }
+
+        /// <summary>
+        /// Weitere Erläuterung zur gewählten Zahlart.
+        /// </summary>
+        [JsonProperty("paymentMethodDetail", NullValueHandling = NullValueHandling.Ignore)]
+        [JsonConverter(typeof(PurpleMinMaxLengthCheckConverter))]
+        public string PaymentMethodDetail { get; set; }
+
+        /// <summary>
+        /// - INITIAL - der Einreichung hat einen Payment-Request ausgelöst und eine
+        /// Payment-Transaction wurde angelegt. Der Nutzer hat aber im Bezahldienst noch keine
+        /// Wirkung erzeugt.
+        /// - BOOKED - der Nutzer hat die Bezahlung im Bezahldienst autorisiert.
+        /// - FAILED - der Vorgang wurde vom Bezahldienst aufgrund der Nutzereingaben abgebrochen.
+        /// - CANCELED - der Nutzer hat die Bezahlung im Bezahldienst abgebrochen.
+        /// </summary>
+        [JsonProperty("status")]
+        public Status Status { get; set; }
+
+        /// <summary>
+        /// Eine vom Bezahldienst vergebene Transaktions-Id.
+        /// </summary>
+        [JsonProperty("transactionId")]
+        [JsonConverter(typeof(PurpleMinMaxLengthCheckConverter))]
+        public string TransactionId { get; set; }
+
+        /// <summary>
+        /// Bezahlreferenz bzw. Verwendungszweck, wie z. B. ein Kassenzeichen.
+        /// </summary>
+        [JsonProperty("transactionReference")]
+        public string TransactionReference { get; set; }
+
+        /// <summary>
+        /// Zeitstempel der erfolgreichen Durchführung der Bezahlung.
+        /// </summary>
+        [JsonProperty("transactionTimestamp", NullValueHandling = NullValueHandling.Ignore)]
+        public DateTimeOffset? TransactionTimestamp { get; set; }
+
+        /// <summary>
+        /// Die Rest-URL der Payment Transaction für die Statusabfrage.
+        /// </summary>
+        [JsonProperty("transactionUrl", NullValueHandling = NullValueHandling.Ignore)]
+        public Uri TransactionUrl { get; set; }
+    }
+
+    /// <summary>
+    /// Beschreibung der Art der Verwaltungsleistung. Eine Verwaltungsleistung sollte immer mit
+    /// einer LeiKa-Id beschrieben werden. Ist für die gegebene Verwaltungsleistung keine
+    /// LeiKa-Id vorhanden, kann die Verwaltungsleistung übergangsweise über die Angabe einer
+    /// anderen eindeutigen Schema-URN beschrieben werden.
+    /// </summary>
+    public partial class Verwaltungsleistung
+    {
+        /// <summary>
+        /// (Kurz-)Beschreibung der Verwaltungsleistung
+        /// </summary>
+        [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// URN einer Leistung. Im Falle einer Leistung aus dem Leistungskatalog sollte hier
+        /// `urn:de:fim:leika:leistung:` vorangestellt werden.
+        /// </summary>
+        [JsonProperty("identifier")]
+        [JsonConverter(typeof(FluffyMinMaxLengthCheckConverter))]
+        public string Identifier { get; set; }
+
+        /// <summary>
+        /// Name/Bezeichnung der Verwaltungsleistung
+        /// </summary>
+        [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
+        public string Name { get; set; }
+    }
+
+    public partial class ReplyChannel
+    {
+        /// <summary>
+        /// Akkreditierte Anbieter siehe
+        /// https://www.bsi.bund.de/DE/Themen/Oeffentliche-Verwaltung/Moderner-Staat/De-Mail/Akkreditierte-DMDA/akkreditierte-dmda_node.html
+        /// </summary>
+        [JsonProperty("deMail", NullValueHandling = NullValueHandling.Ignore)]
+        public DeMail DeMail { get; set; }
+
+        /// <summary>
+        /// Siehe https://www.elster.de/elsterweb/infoseite/elstertransfer_hilfe_schnittstellen
+        /// </summary>
+        [JsonProperty("elster", NullValueHandling = NullValueHandling.Ignore)]
+        public Elster Elster { get; set; }
+
+        [JsonProperty("eMail", NullValueHandling = NullValueHandling.Ignore)]
+        public EMail EMail { get; set; }
+
+        /// <summary>
+        /// Postfachadresse in einem interoperablen Servicekonto (FINK.PFISK)
+        /// </summary>
+        [JsonProperty("fink", NullValueHandling = NullValueHandling.Ignore)]
+        public Fink Fink { get; set; }
+    }
+
+    /// <summary>
+    /// Akkreditierte Anbieter siehe
+    /// https://www.bsi.bund.de/DE/Themen/Oeffentliche-Verwaltung/Moderner-Staat/De-Mail/Akkreditierte-DMDA/akkreditierte-dmda_node.html
+    /// </summary>
+    public partial class DeMail
+    {
+        [JsonProperty("address")]
+        public string Address { get; set; }
+    }
+
+    public partial class EMail
+    {
+        [JsonProperty("address")]
+        public string Address { get; set; }
+
+        /// <summary>
+        /// Hilfe zur Erstellung gibt es in der Dokumentation unter
+        /// https://docs.fitko.de/fit-connect/details/pgp-export
+        /// </summary>
+        [JsonProperty("pgpPublicKey", NullValueHandling = NullValueHandling.Ignore)]
+        public string PgpPublicKey { get; set; }
+    }
+
+    /// <summary>
+    /// Siehe https://www.elster.de/elsterweb/infoseite/elstertransfer_hilfe_schnittstellen
+    /// </summary>
+    public partial class Elster
+    {
+        [JsonProperty("accountId")]
+        public string AccountId { get; set; }
+
+        [JsonProperty("geschaeftszeichen", NullValueHandling = NullValueHandling.Ignore)]
+        [JsonConverter(typeof(TentacledMinMaxLengthCheckConverter))]
+        public string Geschaeftszeichen { get; set; }
+
+        [JsonProperty("lieferTicket", NullValueHandling = NullValueHandling.Ignore)]
+        public string LieferTicket { get; set; }
+    }
+
+    /// <summary>
+    /// Postfachadresse in einem interoperablen Servicekonto (FINK.PFISK)
+    /// </summary>
+    public partial class Fink
+    {
+        /// <summary>
+        /// FINK Postfachadresse
+        /// </summary>
+        [JsonProperty("finkPostfachRef")]
+        [JsonConverter(typeof(StickyMinMaxLengthCheckConverter))]
+        public string FinkPostfachRef { get; set; }
+
+        /// <summary>
+        /// URL des Servicekontos, in dem das Ziel-Postfach liegt
+        /// </summary>
+        [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)]
+        public Uri Host { get; set; }
+    }
+
+    /// <summary>
+    /// Definiert die Art des Identifikationsnachweises.
+    /// </summary>
+    public enum AuthenticationInformationType { IdentificationReport };
+
+    /// <summary>
+    /// Der verwendete Hash-Algorithmus. Derzeit ist nur `sha512` erlaubt.
+    /// </summary>
+    public enum HashType { Sha512 };
+
+    /// <summary>
+    /// Zweck/Art der Anlage
+    /// - form: Automatisch generierte PDF-Repräsentation des vollständigen Antragsformulars
+    /// - attachment: Anlage, die von einem Bürger hochgeladen wurde
+    /// - report: Vom Onlinedienst, nachträglich erzeugte Unterlage
+    /// </summary>
+    public enum Purpose { Attachment, Form, Report };
+
+    /// <summary>
+    /// Referenziert ein eindeutiges Profil einer AdES (advanced electronic signature/seal)
+    /// gemäß eIDAS-Verordnung über eine URI gemäß [ETSI TS 119
+    /// 192](https://www.etsi.org/deliver/etsi_ts/119100_119199/119192/01.01.01_60/ts_119192v010101p.pdf).
+    ///
+    /// Für die Details zur Verwendung und Validierung von Profilen siehe auch
+    /// https://ec.europa.eu/cefdigital/DSS/webapp-demo/doc/dss-documentation.html#_signatures_profile_simplification
+    /// </summary>
+    public enum EidasAdesProfile { HttpUriEtsiOrgAdes191X2LevelBaselineBB, HttpUriEtsiOrgAdes191X2LevelBaselineBLt, HttpUriEtsiOrgAdes191X2LevelBaselineBLta, HttpUriEtsiOrgAdes191X2LevelBaselineBT };
+
+    /// <summary>
+    /// Beschreibt, welches Signaturformat die genutzte Signatur / das genutzte Siegel nutzt.
+    /// Aktuell wird die Hinterlegung folgender Signaturformate unterstützt: CMS = Cryptographic
+    /// Message Syntax, Asic = Associated Signature Containers, PDF = PDF Signatur, XML =
+    /// XML-Signature, JSON = JSON Web Signature.
+    /// </summary>
+    public enum SignatureFormat { Asic, Cms, Json, Pdf, Xml };
+
+    /// <summary>
+    /// Mimetype (z.B. application/json oder application/xml) des referenzierten Schemas (z.B.
+    /// XSD- oder JSON-Schema).
+    /// </summary>
+    public enum MimeType { ApplicationJson, ApplicationXml };
+
+    /// <summary>
+    /// Die vom Benutzer ausgewählte Zahlart. Das Feld ist nur bei einer erfolgreichen Zahlung
+    /// vorhanden / befüllt.
+    /// </summary>
+    public enum PaymentMethod { Creditcard, Giropay, Invoice, Other, Paydirect, Paypal };
+
+    /// <summary>
+    /// - INITIAL - der Einreichung hat einen Payment-Request ausgelöst und eine
+    /// Payment-Transaction wurde angelegt. Der Nutzer hat aber im Bezahldienst noch keine
+    /// Wirkung erzeugt.
+    /// - BOOKED - der Nutzer hat die Bezahlung im Bezahldienst autorisiert.
+    /// - FAILED - der Vorgang wurde vom Bezahldienst aufgrund der Nutzereingaben abgebrochen.
+    /// - CANCELED - der Nutzer hat die Bezahlung im Bezahldienst abgebrochen.
+    /// </summary>
+    public enum Status { Booked, Canceled, Failed, Initial };
+
+    public partial class Metadata
+    {
+        public static Metadata FromJson(string json) => JsonConvert.DeserializeObject<Metadata>(json, FitConnect.Models.Api.Set.Converter.Settings);
+    }
+
+    public static class Serialize
+    {
+        public static string ToJson(this Metadata self) => JsonConvert.SerializeObject(self, FitConnect.Models.Api.Set.Converter.Settings);
+    }
+
+    internal static class Converter
+    {
+        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
+        {
+            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
+            DateParseHandling = DateParseHandling.None,
+            Converters =
+            {
+                AuthenticationInformationTypeConverter.Singleton,
+                HashTypeConverter.Singleton,
+                PurposeConverter.Singleton,
+                EidasAdesProfileConverter.Singleton,
+                SignatureFormatConverter.Singleton,
+                MimeTypeConverter.Singleton,
+                PaymentMethodConverter.Singleton,
+                StatusConverter.Singleton,
+                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
+            },
+        };
+    }
+
+    internal class AuthenticationInformationTypeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(AuthenticationInformationType) || t == typeof(AuthenticationInformationType?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            if (value == "identificationReport")
+            {
+                return AuthenticationInformationType.IdentificationReport;
+            }
+            throw new Exception("Cannot unmarshal type AuthenticationInformationType");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (AuthenticationInformationType)untypedValue;
+            if (value == AuthenticationInformationType.IdentificationReport)
+            {
+                serializer.Serialize(writer, "identificationReport");
+                return;
+            }
+            throw new Exception("Cannot marshal type AuthenticationInformationType");
+        }
+
+        public static readonly AuthenticationInformationTypeConverter Singleton = new AuthenticationInformationTypeConverter();
+    }
+
+    internal class HashTypeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(HashType) || t == typeof(HashType?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            if (value == "sha512")
+            {
+                return HashType.Sha512;
+            }
+            throw new Exception("Cannot unmarshal type HashType");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (HashType)untypedValue;
+            if (value == HashType.Sha512)
+            {
+                serializer.Serialize(writer, "sha512");
+                return;
+            }
+            throw new Exception("Cannot marshal type HashType");
+        }
+
+        public static readonly HashTypeConverter Singleton = new HashTypeConverter();
+    }
+
+    internal class PurposeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(Purpose) || t == typeof(Purpose?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "attachment":
+                    return Purpose.Attachment;
+                case "form":
+                    return Purpose.Form;
+                case "report":
+                    return Purpose.Report;
+            }
+            throw new Exception("Cannot unmarshal type Purpose");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (Purpose)untypedValue;
+            switch (value)
+            {
+                case Purpose.Attachment:
+                    serializer.Serialize(writer, "attachment");
+                    return;
+                case Purpose.Form:
+                    serializer.Serialize(writer, "form");
+                    return;
+                case Purpose.Report:
+                    serializer.Serialize(writer, "report");
+                    return;
+            }
+            throw new Exception("Cannot marshal type Purpose");
+        }
+
+        public static readonly PurposeConverter Singleton = new PurposeConverter();
+    }
+
+    internal class EidasAdesProfileConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(EidasAdesProfile) || t == typeof(EidasAdesProfile?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-B#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBB;
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-LT#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLt;
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-LTA#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLta;
+                case "http://uri.etsi.org/ades/191x2/level/baseline/B-T#":
+                    return EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBT;
+            }
+            throw new Exception("Cannot unmarshal type EidasAdesProfile");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (EidasAdesProfile)untypedValue;
+            switch (value)
+            {
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBB:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-B#");
+                    return;
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLt:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-LT#");
+                    return;
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBLta:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-LTA#");
+                    return;
+                case EidasAdesProfile.HttpUriEtsiOrgAdes191X2LevelBaselineBT:
+                    serializer.Serialize(writer, "http://uri.etsi.org/ades/191x2/level/baseline/B-T#");
+                    return;
+            }
+            throw new Exception("Cannot marshal type EidasAdesProfile");
+        }
+
+        public static readonly EidasAdesProfileConverter Singleton = new EidasAdesProfileConverter();
+    }
+
+    internal class SignatureFormatConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(SignatureFormat) || t == typeof(SignatureFormat?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "asic":
+                    return SignatureFormat.Asic;
+                case "cms":
+                    return SignatureFormat.Cms;
+                case "json":
+                    return SignatureFormat.Json;
+                case "pdf":
+                    return SignatureFormat.Pdf;
+                case "xml":
+                    return SignatureFormat.Xml;
+            }
+            throw new Exception("Cannot unmarshal type SignatureFormat");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (SignatureFormat)untypedValue;
+            switch (value)
+            {
+                case SignatureFormat.Asic:
+                    serializer.Serialize(writer, "asic");
+                    return;
+                case SignatureFormat.Cms:
+                    serializer.Serialize(writer, "cms");
+                    return;
+                case SignatureFormat.Json:
+                    serializer.Serialize(writer, "json");
+                    return;
+                case SignatureFormat.Pdf:
+                    serializer.Serialize(writer, "pdf");
+                    return;
+                case SignatureFormat.Xml:
+                    serializer.Serialize(writer, "xml");
+                    return;
+            }
+            throw new Exception("Cannot marshal type SignatureFormat");
+        }
+
+        public static readonly SignatureFormatConverter Singleton = new SignatureFormatConverter();
+    }
+
+    internal class MimeTypeConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(MimeType) || t == typeof(MimeType?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "application/json":
+                    return MimeType.ApplicationJson;
+                case "application/xml":
+                    return MimeType.ApplicationXml;
+            }
+            throw new Exception("Cannot unmarshal type MimeType");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (MimeType)untypedValue;
+            switch (value)
+            {
+                case MimeType.ApplicationJson:
+                    serializer.Serialize(writer, "application/json");
+                    return;
+                case MimeType.ApplicationXml:
+                    serializer.Serialize(writer, "application/xml");
+                    return;
+            }
+            throw new Exception("Cannot marshal type MimeType");
+        }
+
+        public static readonly MimeTypeConverter Singleton = new MimeTypeConverter();
+    }
+
+    internal class MinMaxValueCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(double) || t == typeof(double?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<double>(reader);
+            if (value >= 0.01)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type double");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (double)untypedValue;
+            if (value >= 0.01)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type double");
+        }
+
+        public static readonly MinMaxValueCheckConverter Singleton = new MinMaxValueCheckConverter();
+    }
+
+    internal class PaymentMethodConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(PaymentMethod) || t == typeof(PaymentMethod?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "CREDITCARD":
+                    return PaymentMethod.Creditcard;
+                case "GIROPAY":
+                    return PaymentMethod.Giropay;
+                case "INVOICE":
+                    return PaymentMethod.Invoice;
+                case "OTHER":
+                    return PaymentMethod.Other;
+                case "PAYDIRECT":
+                    return PaymentMethod.Paydirect;
+                case "PAYPAL":
+                    return PaymentMethod.Paypal;
+            }
+            throw new Exception("Cannot unmarshal type PaymentMethod");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (PaymentMethod)untypedValue;
+            switch (value)
+            {
+                case PaymentMethod.Creditcard:
+                    serializer.Serialize(writer, "CREDITCARD");
+                    return;
+                case PaymentMethod.Giropay:
+                    serializer.Serialize(writer, "GIROPAY");
+                    return;
+                case PaymentMethod.Invoice:
+                    serializer.Serialize(writer, "INVOICE");
+                    return;
+                case PaymentMethod.Other:
+                    serializer.Serialize(writer, "OTHER");
+                    return;
+                case PaymentMethod.Paydirect:
+                    serializer.Serialize(writer, "PAYDIRECT");
+                    return;
+                case PaymentMethod.Paypal:
+                    serializer.Serialize(writer, "PAYPAL");
+                    return;
+            }
+            throw new Exception("Cannot marshal type PaymentMethod");
+        }
+
+        public static readonly PaymentMethodConverter Singleton = new PaymentMethodConverter();
+    }
+
+    internal class PurpleMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length >= 1 && value.Length <= 36)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length >= 1 && value.Length <= 36)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly PurpleMinMaxLengthCheckConverter Singleton = new PurpleMinMaxLengthCheckConverter();
+    }
+
+    internal class StatusConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(Status) || t == typeof(Status?);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            if (reader.TokenType == JsonToken.Null) return null;
+            var value = serializer.Deserialize<string>(reader);
+            switch (value)
+            {
+                case "BOOKED":
+                    return Status.Booked;
+                case "CANCELED":
+                    return Status.Canceled;
+                case "FAILED":
+                    return Status.Failed;
+                case "INITIAL":
+                    return Status.Initial;
+            }
+            throw new Exception("Cannot unmarshal type Status");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            if (untypedValue == null)
+            {
+                serializer.Serialize(writer, null);
+                return;
+            }
+            var value = (Status)untypedValue;
+            switch (value)
+            {
+                case Status.Booked:
+                    serializer.Serialize(writer, "BOOKED");
+                    return;
+                case Status.Canceled:
+                    serializer.Serialize(writer, "CANCELED");
+                    return;
+                case Status.Failed:
+                    serializer.Serialize(writer, "FAILED");
+                    return;
+                case Status.Initial:
+                    serializer.Serialize(writer, "INITIAL");
+                    return;
+            }
+            throw new Exception("Cannot marshal type Status");
+        }
+
+        public static readonly StatusConverter Singleton = new StatusConverter();
+    }
+
+    internal class FluffyMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length >= 7 && value.Length <= 255)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length >= 7 && value.Length <= 255)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly FluffyMinMaxLengthCheckConverter Singleton = new FluffyMinMaxLengthCheckConverter();
+    }
+
+    internal class TentacledMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length <= 10)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length <= 10)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly TentacledMinMaxLengthCheckConverter Singleton = new TentacledMinMaxLengthCheckConverter();
+    }
+
+    internal class StickyMinMaxLengthCheckConverter : JsonConverter
+    {
+        public override bool CanConvert(Type t) => t == typeof(string);
+
+        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
+        {
+            var value = serializer.Deserialize<string>(reader);
+            if (value.Length <= 150)
+            {
+                return value;
+            }
+            throw new Exception("Cannot unmarshal type string");
+        }
+
+        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
+        {
+            var value = (string)untypedValue;
+            if (value.Length <= 150)
+            {
+                serializer.Serialize(writer, value);
+                return;
+            }
+            throw new Exception("Cannot marshal type string");
+        }
+
+        public static readonly StickyMinMaxLengthCheckConverter Singleton = new StickyMinMaxLengthCheckConverter();
+    }
+}
diff --git a/Services/Models/Submission/SubmitSubmissionDto.cs b/Services/Models/Submission/SubmitSubmissionDto.cs
index ec47ff8a5fe4adc0f8c9e46ffc8fc5728d407c65..db1e7d96e679ee03789fd908098db26d64c538e6 100644
--- a/Services/Models/Submission/SubmitSubmissionDto.cs
+++ b/Services/Models/Submission/SubmitSubmissionDto.cs
@@ -4,7 +4,7 @@ namespace FitConnect.Services.Models;
 
 public class SubmitSubmissionDto {
     [JsonPropertyName("encryptedData")]
-    public string EncryptedData;
+    public string? EncryptedData;
 
     [JsonPropertyName("encryptedMetadata")]
     public string EncryptedMetadata;
diff --git a/Services/Services.csproj b/Services/Services.csproj
index 9532ca430385e7c6b1f9774a9064d4bcfebbb013..a7e0e4428d4d28e78ac79e675b28c5102e5ba1ad 100644
--- a/Services/Services.csproj
+++ b/Services/Services.csproj
@@ -8,12 +8,12 @@
     </PropertyGroup>
 
     <ItemGroup>
-        <ProjectReference Include="..\Models\Models.csproj"/>
-        <ProjectReference Include="..\RestService\RestService.csproj"/>
+        <ProjectReference Include="..\Models\Models.csproj" />
+        <ProjectReference Include="..\RestService\RestService.csproj" />
     </ItemGroup>
 
     <ItemGroup>
-        <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1"/>
+        <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
     </ItemGroup>
 
 </Project>
diff --git a/readme.md b/readme.md
index b1f41534b6db438a9c870a42502b0807adbb13b4..ab8a5455732c3c092b77b09577f99fb339e35953 100644
--- a/readme.md
+++ b/readme.md
@@ -133,6 +133,21 @@ You need a secret file for e2e test like:
 }
 ```
 
+# API Abstraction
+
+```mermaid
+    sequenceDiagram
+        Client->>FitConnectServer: SendSubmission
+        FitConnectServer->>Client: Success
+```
+
+## The sender process
+```mermaid
+    sequenceDiagram
+        Sender->>FitConnectServer: GetSubmissions
+        FitConnectServer->>Sender: Success
+```
+
 [glossary](https://docs.fitko.de/fit-connect/docs/glossary/)
 
 ### Tickets