Index: TFP-WebServer/WebServer/WebServer.csproj
===================================================================
--- TFP-WebServer/WebServer/WebServer.csproj	(revision 459)
+++ TFP-WebServer/WebServer/WebServer.csproj	(revision 460)
@@ -198,4 +198,9 @@
   </ItemGroup>
   <ItemGroup>
+    <EmbeddedResource Include="src\WebAPI\APIs\GameData\Item.openapi.yaml" />
+    <EmbeddedResource Include="src\WebAPI\APIs\GameData\Mods.openapi.yaml" />
+    <EmbeddedResource Include="src\WebAPI\APIs\Log.openapi.yaml" />
+    <EmbeddedResource Include="src\WebAPI\APIs\Command.openapi.yaml" />
+    <EmbeddedResource Include="src\WebAPI\APIs\Permissions\Blacklist.openapi.yaml" />
     <EmbeddedResource Include="src\WebAPI\APIs\WorldState\Animal.openapi.yaml" />
     <EmbeddedResource Include="src\WebAPI\OpenAPI.master.yaml" />
Index: TFP-WebServer/WebServer/src/UrlHandlers/ApiHandler.cs
===================================================================
--- TFP-WebServer/WebServer/src/UrlHandlers/ApiHandler.cs	(revision 459)
+++ TFP-WebServer/WebServer/src/UrlHandlers/ApiHandler.cs	(revision 460)
@@ -53,4 +53,22 @@
 		private static readonly UnityEngine.Profiling.CustomSampler apiHandlerSampler = UnityEngine.Profiling.CustomSampler.Create ("API_Handler");
 
+		private bool HandleCors (RequestContext _context) {
+			_context.Request.Headers.TryGetValue ("Origin", out string origin);
+			_context.Response.AddHeader ("Access-Control-Allow-Origin", origin ?? "*");
+
+			if (_context.Method != ERequestMethod.OPTIONS) {
+				return false;
+			}
+
+			if (!_context.Request.Headers.TryGetValue ("Access-Control-Request-Method", out _)) {
+				return false;
+			}
+
+			_context.Response.AddHeader ("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS, HEAD");
+			_context.Response.AddHeader ("Access-Control-Allow-Headers", "X-SDTD-API-TOKENNAME, X-SDTD-API-SECRET");
+			_context.Response.AddHeader ("Access-Control-Allow-Credentials", "true");
+			return true;
+		}
+
 		public override void HandleRequest (RequestContext _context) {
 
@@ -72,4 +90,10 @@
 			}
 
+			// CORS specific stuff
+			if (HandleCors (_context)) {
+				return;
+			}
+			// CORS end
+			
 			_context.RequestPath = subPath;
 
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/Command.openapi.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/Command.openapi.yaml	(revision 460)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/Command.openapi.yaml	(revision 460)
@@ -0,0 +1,206 @@
+openapi: 3.1.0
+info:
+  title: Command
+  version: '1'
+
+components:
+  schemas:
+    CommandElement:
+      type: object
+      properties:
+        overloads:
+          type: array
+          items:
+            type: string
+          examples:
+            - [listplayers, lp]
+          description: Overload names for the command, including the main command name
+        command:
+          type: string
+          examples:
+            - listplayers
+          description: Main command name
+        description:
+          type: string
+          examples:
+            - lists all players
+          description: Short description text for the command
+        help:
+          type:
+            - string
+            - 'null'
+          description: Help text for the command if defined, null otherwise
+        allowed:
+          type: boolean
+          description: Can the command be executed with the permission level active for this request?
+      required:
+        - overloads
+        - command
+        - description
+
+    CommandsList:
+      type: array
+      items:
+        $ref: '#/components/schemas/CommandElement'
+
+    CommandsResult:
+      type: object
+      properties:
+        commands:
+          $ref: '#/components/schemas/CommandsList'
+      required:
+        - commands
+
+    CommandExecutedResultFull:
+      type: object
+      properties:
+        command:
+          type: string
+          examples:
+            - 'settime'
+          description: The command executed without arguments
+        parameters:
+          type: string
+          examples:
+            - '1 13 37'
+          description: The arguments of the executed command
+        result:
+          type: string
+          examples:
+            - 'Set time to 13616'
+          description: The output of the executed command
+      required:
+        - command
+        - parameters
+        - result
+      description: Full style command result
+      
+    CommandExecutedResultSimple:
+      type: object
+      properties:
+        resultRaw:
+          type: string
+          examples:
+            - 'Set time to 13616'
+          description: The output of the executed command
+      required:
+        - resultRaw
+      description: Simple style command result
+
+
+  requestBodies:
+    CommandBodyIn:
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              command:
+                type: string
+                examples:
+                  - 'settime 1 13 37'
+                description: Command to be executed, including any arguments
+              format:
+                type: string
+                enum:
+                  - Full
+                  - Simple
+                  - Raw
+                description: Expected format of the returned execution result. Full being a full JSON object with info on the executed command and result, simple only returning a JSON object with the execution result and raw returning the execution result as plain text.
+            required:
+              - command
+      required: true
+
+
+  responses:
+    CommandsBodyOut:
+      description: Found commands
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              data:
+                $ref: '#/components/schemas/CommandsResult'
+              meta:
+                $ref: './openapi.yaml#/components/schemas/ResultEnvelopeMeta'
+            required:
+              - data
+              - meta
+
+
+  parameters:
+    CommandNameParameter:
+      name: name
+      in: path
+      required: true
+      schema:
+        type: string
+      description: Name of command to fetch
+
+
+paths:
+  /api/command:
+    get:
+      tags:
+        - Commands
+      summary: Commands list
+      description: Fetch a list of all commands
+      operationId: command.get
+      responses:
+        200:
+          description: List of commands
+          $ref: '#/components/responses/CommandsBodyOut'
+
+    post:
+      tags:
+        - Commands
+      summary: Command execute
+      description: Execute a command
+      operationId: command.post
+      requestBody:
+        $ref: '#/components/requestBodies/CommandBodyIn'
+      responses:
+        200:
+          description: Command executed successfully
+          content: 
+            application/json:
+              schema:
+                oneOf:
+                  - $ref: '#/components/schemas/CommandExecutedResultFull'
+                  - $ref: '#/components/schemas/CommandExecutedResultSimple'
+            text/plain:
+              schema: 
+                type: string
+                examples:
+                  - 'Set time to 13616'
+        400:
+          description: Invalid request body, errorCode will be 'NO_COMMAND'
+          $ref: './openapi.yaml#/components/responses/HttpEmptyEnvelopedResponse'
+        404:
+          description: Command to be executed not found
+          $ref: './openapi.yaml#/components/responses/HttpEmptyEnvelopedResponse'
+        403:
+          description: Not allowed to execute the given command
+          $ref: './openapi.yaml#/components/responses/Unauthorized'
+      security:
+        - apiTokenName: []
+          apiTokenSecret: []
+        - sessionCookie: []
+
+  /api/command/{name}:
+    get:
+      tags:
+        - Commands
+      summary: Command show
+      description: Get info on a specific command
+      operationId: command.get.id
+      parameters:
+        - $ref: '#/components/parameters/CommandNameParameter'
+      responses:
+        200:
+          description: Single command
+          $ref: '#/components/responses/CommandsBodyOut'
+        404:
+          description: Command not found
+          $ref: './openapi.yaml#/components/responses/HttpEmptyEnvelopedResponse'
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/GameData/Item.openapi.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/GameData/Item.openapi.yaml	(revision 460)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/GameData/Item.openapi.yaml	(revision 460)
@@ -0,0 +1,54 @@
+openapi: 3.1.0
+info:
+  title: Item
+  version: '1'
+
+components:
+  schemas:
+    ItemElement:
+      type: object
+      properties:
+        name:
+          type: string
+          examples:
+            - woodShapes:VariantHelper
+        localizedName:
+          type: string
+          examples:
+            - Wood Block
+        isBlock:
+          type: boolean
+      required:
+        - name
+        - localizedName
+        - isBlock
+
+    ItemList:
+      type: array
+      items:
+        $ref: '#/components/schemas/ItemElement'
+
+
+paths:
+  /api/item:
+    get:
+      tags:
+        - GameData
+      summary: Items list
+      description: Fetch a list of defined items
+      operationId: item.get
+      responses:
+        200:
+          description: List of items
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  data:
+                    $ref: '#/components/schemas/ItemList'
+                  meta:
+                    $ref: './openapi.yaml#/components/schemas/ResultEnvelopeMeta'
+                required:
+                  - data
+                  - meta
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/GameData/Mods.openapi.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/GameData/Mods.openapi.yaml	(revision 460)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/GameData/Mods.openapi.yaml	(revision 460)
@@ -0,0 +1,83 @@
+openapi: 3.1.0
+info:
+  title: Mods
+  version: '1'
+
+components:
+  schemas:
+    ModElement:
+      type: object
+      properties:
+        name:
+          type: string
+          examples:
+            - TFP_WebServer
+        displayName:
+          type: string
+          examples:
+            - Web Dashboard
+        description:
+          type: string
+          examples:
+            - Integrated Webserver for the Web Dashboard and server APIs
+        author:
+          type: string
+          examples:
+            - The Fun Pimps LLC
+        version:
+          type: string
+          examples:
+            - 21.1.15.0
+        website:
+          type: string
+          format: uri
+          examples:
+            - ''
+        web:
+          type: object
+          properties:
+            bundle:
+              type: string
+              examples:
+                - /webmods/Xample_MarkersMod/bundle.js
+            css:
+              type: string
+              examples:
+                - /webmods/Xample_MarkersMod/styling.css
+      required:
+        - name
+        - displayName
+        - description
+        - author
+        - version
+        - website
+
+    ModsList:
+      type: array
+      items:
+        $ref: '#/components/schemas/ModElement'
+
+
+paths:
+  /api/mods:
+    get:
+      tags:
+        - GameData
+      summary: Mods list
+      description: Fetch a list of loaded mods
+      operationId: mods.get
+      responses:
+        200:
+          description: List of mods
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  data:
+                    $ref: '#/components/schemas/ModsList'
+                  meta:
+                    $ref: './openapi.yaml#/components/schemas/ResultEnvelopeMeta'
+                required:
+                  - data
+                  - meta
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/Log.openapi.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/Log.openapi.yaml	(revision 460)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/Log.openapi.yaml	(revision 460)
@@ -0,0 +1,114 @@
+openapi: 3.1.0
+info:
+  title: Log
+  version: '1'
+
+components:
+  schemas:
+    LogEntry:
+      type: object
+      properties: 
+        msg:
+          type: string
+          examples:
+            - 'Version: Alpha 21 (b48) Compatibility Version: Alpha 21, Build: WindowsPlayer 64 Bit'
+          description: Message
+        type:
+          type: string
+          enum:
+            - Error
+            - Assert
+            - Warning
+            - Log
+            - Exception
+          description: Severity type
+        trace:
+          type: string
+          description: Stacktrace if entry is an Exception
+        isotime:
+          type: string
+          format: date-time
+        uptime:
+          type: string
+          examples:
+            - '87123'
+          description: Time since server was started in milliseconds.
+      required:
+        - msg
+        - type
+        - trace
+        - isotime
+        - uptime
+      
+    LogData:
+      type: object
+      properties: 
+        entries:
+          type: array
+          items:
+            $ref: '#/components/schemas/LogEntry'
+        firstLine:
+          type: integer
+          examples:
+            - 47
+          description: Number of first line retrieved
+        lastLine:
+          type: integer
+          examples:
+            - 48
+          description: Number of next line to retrieve to follow up without missing entries
+      required:
+        - entries
+        - firstLine
+        - lastLine
+
+
+  parameters:
+    LogCountParameter:
+      name: count
+      in: query
+      required: false
+      schema:
+        type: integer
+      description: Number of lines to fetch. If negative fetches count lines from the firstLine. Defaults to 50.
+
+    LogFirstLineParameter:
+      name: firstLine
+      in: query
+      required: false
+      schema:
+        type: integer
+      description: First line number to fetch. Defaults to the oldest stored log line if count is positive. Defaults to the most recent log line if count is negative.
+
+paths:
+  /api/Log:
+    get:
+      tags:
+        - Log
+      summary: Log
+      description: Get an amount of lines from the server log
+      operationId: log.get
+      parameters:
+        - $ref: '#/components/parameters/LogCountParameter'
+        - $ref: '#/components/parameters/LogFirstLineParameter'
+      responses:
+        200:
+          description: Log information
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  data:
+                    $ref: '#/components/schemas/LogData'
+                  meta:
+                    $ref: './openapi.yaml#/components/schemas/ResultEnvelopeMeta'
+                required:
+                  - data
+                  - meta
+        403:
+          $ref: './openapi.yaml#/components/responses/Unauthorized'
+      security:
+        - apiTokenName: []
+          apiTokenSecret: []
+        - sessionCookie: []
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/OpenAPI.openapi.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/OpenAPI.openapi.yaml	(revision 459)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/OpenAPI.openapi.yaml	(revision 460)
@@ -2,5 +2,5 @@
 info:
   title: OpenAPI
-  version: 1
+  version: '1'
 
 
@@ -8,4 +8,8 @@
   /api/OpenAPI/openapi.yaml:
     get:
+      tags:
+        - Meta
+      summary: OpenAPI master document
+      description: Fetch the OpenAPI master document, referencing all the individual WebAPI specs
       operationId: OpenAPI.openapi
       responses:
@@ -14,8 +18,10 @@
             application/json: {}
           description: OpenAPI master document
+  /api/OpenAPI/{name}.openapi.yaml:
+    get:
       tags:
         - Meta
-  /api/OpenAPI/{name}.openapi.yaml:
-    get:
+      summary: OpenAPI spec for single API
+      description: Fetch the OpenAPI spec of a single WebAPI
       operationId: OpenAPI.getAPI
       parameters:
@@ -35,4 +41,2 @@
             application/json: {}
           description: No OpenAPI spec found for the API name
-      tags:
-        - Meta
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/Permissions/Blacklist.cs
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/Permissions/Blacklist.cs	(revision 459)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/Permissions/Blacklist.cs	(revision 460)
@@ -100,10 +100,10 @@
 			}
 
-			bool validId = PlatformUserIdentifierAbs.TryFromCombinedString (id, out _userId);
-			if (!validId) {
+			if (PlatformUserIdentifierAbs.TryFromCombinedString (id, out _userId)) {
 				SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, "INVALID_USER");
+				return false;
 			}
 
-			return validId;
+			return true;
 		}
 
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/Permissions/Blacklist.openapi.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/Permissions/Blacklist.openapi.yaml	(revision 460)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/Permissions/Blacklist.openapi.yaml	(revision 460)
@@ -0,0 +1,160 @@
+openapi: 3.1.0
+info:
+  title: Blacklist
+  version: '1'
+
+components:
+  schemas:
+    BlacklistElement:
+      type: object
+      properties:
+        name:
+          type: string
+          examples:
+            - TheFunPimp
+          description: Name of the banned player for display purposes. Can be empty.
+        userId:
+          $ref: './openapi.yaml#/components/schemas/TypeUserIdObject'
+        bannedUntil:
+          type: string
+          format: date-time
+        banReason:
+          type: string
+          examples:
+            - Cheating not allowed!
+      required:
+        - name
+        - userId
+        - bannedUntil
+        - banReason
+
+    BlacklistList:
+      type: array
+      items:
+        $ref: '#/components/schemas/BlacklistElement'
+
+
+  requestBodies:
+    BlacklistBodyIn:
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              x:
+                type: integer
+                examples:
+                  - -43
+              y:
+                type: integer
+                examples:
+                  - 842
+              icon:
+                type: string
+                format: uuid
+                examples:
+                  - https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Blue_question_mark_icon.svg/1200px-Blue_question_mark_icon.svg.png
+            required:
+              - x
+              - y
+      required: true
+
+
+  parameters:
+    UserIdPathParameter:
+      name: id
+      in: path
+      required: true
+      schema:
+        $ref: '#/components/schemas/TypeUserIdString'
+
+
+paths:
+  /api/blacklist:
+    get:
+      tags:
+        - Permissions
+      summary: Blacklist list
+      description: Fetch a list of all blacklisted users
+      operationId: blacklist.get
+      responses:
+        200:
+          description: List of found markers
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  data:
+                    $ref: '#/components/schemas/BlacklistList'
+                  meta:
+                    $ref: './openapi.yaml#/components/schemas/ResultEnvelopeMeta'
+                required:
+                  - data
+                  - meta
+
+
+  /api/blacklist/{id}:
+#    get:
+#      tags:
+#        - Permissions
+#      summary: Marker show
+#      description: Fetch a single defined map marker
+#      operationId: blacklist.get.id
+#      parameters:
+#        - $ref: '#/components/parameters/MarkerIdParameter'
+#      responses:
+#        200:
+#          description: Single found marker
+#          $ref: '#/components/responses/MarkersBodyOut'
+#        404:
+#          description: Marker ID not found, errorCode will be 'ID_NOT_FOUND'
+#          $ref: '#/components/responses/HttpEmptyEnvelopedResponse'
+
+    post:
+      tags:
+        - Permissions
+      summary: Blacklist create
+      description: Create or update a blacklist entry
+      operationId: blacklist.post.id
+      parameters:
+        - $ref: '#/components/parameters/UserIdPathParameter'
+      requestBody:
+        $ref: '#/components/requestBodies/BlacklistBodyIn'
+      responses:
+        201:
+          description: Marker with updated values
+          $ref: './openapi.yaml#/components/responses/HttpEmptyEnvelopedResponse'
+        400:
+          description: >-
+            Invalid request body, errorCode will be one of 'NO_OR_INVALID_X',
+            'NO_OR_INVALID_Y'
+          $ref: './openapi.yaml#/components/responses/HttpEmptyEnvelopedResponse'
+        403:
+          $ref: './openapi.yaml#/components/responses/Unauthorized'
+      security:
+        - apiTokenName: []
+          apiTokenSecret: []
+        - sessionCookie: []
+
+    delete:
+      tags:
+        - Permissions
+      summary: Blacklist delete
+      description: Delete a single entry from the blacklist
+      operationId: blacklist.delete.id
+      parameters:
+        - $ref: '#/components/parameters/UserIdPathParameter'
+      responses:
+        204:
+          description: Deleted marker
+          $ref: './openapi.yaml#/components/responses/HttpEmptyEnvelopedResponse'
+        404:
+          description: Marker ID not found
+          $ref: './openapi.yaml#/components/responses/HttpEmptyEnvelopedResponse'
+        403:
+          $ref: './openapi.yaml#/components/responses/Unauthorized'
+      security:
+        - apiTokenName: []
+          apiTokenSecret: []
+        - sessionCookie: []
Index: TFP-WebServer/WebServer/src/WebAPI/APIs/WorldState/Animal.openapi.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/APIs/WorldState/Animal.openapi.yaml	(revision 459)
+++ TFP-WebServer/WebServer/src/WebAPI/APIs/WorldState/Animal.openapi.yaml	(revision 460)
@@ -2,5 +2,5 @@
 info:
   title: Animal
-  version: 1
+  version: '1'
 
 components:
@@ -10,5 +10,5 @@
       properties:
         id:
-          $ref: '#/components/schemas/TypeEntityId'
+          $ref: './openapi.yaml#/components/schemas/TypeEntityId'
         name:
           type: string
@@ -16,5 +16,5 @@
             - animalStag
         position:
-          $ref: '#/components/schemas/TypeVector3i'
+          $ref: './openapi.yaml#/components/schemas/TypeVector3i'
       required:
         - id
@@ -47,10 +47,10 @@
                     $ref: '#/components/schemas/AnimalList'
                   meta:
-                    $ref: '#/components/schemas/ResultEnvelopeMeta'
+                    $ref: './openapi.yaml#/components/schemas/ResultEnvelopeMeta'
                 required:
                   - data
                   - meta
         403:
-          $ref: '#/components/responses/Unauthorized'
+          $ref: './openapi.yaml#/components/responses/Unauthorized'
       security:
         - apiTokenName: []
Index: TFP-WebServer/WebServer/src/WebAPI/OpenAPI.master.yaml
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/OpenAPI.master.yaml	(revision 459)
+++ TFP-WebServer/WebServer/src/WebAPI/OpenAPI.master.yaml	(revision 460)
@@ -1,6 +1,6 @@
+openapi: 3.1.0
 info:
   title: 7 Days To Die WebAPI
-  version: 1.0.0
-openapi: 3.1.0
+  version: '1.0.0'
 servers:
   - url: /
@@ -81,4 +81,35 @@
       description: 3D vector in full blocks
 
+    TypeUserIdString:
+      type: string
+      pattern: '^\[a-zA-Z]+_[\w]+$'
+      examples:
+        - 'Steam_76561198021925107'
+      description: User ID including platform
+
+    TypeUserIdObject:
+      anyOf:
+        - type: object
+          properties:
+            combinedString:
+              $ref: '#/components/schemas/TypeUserIdString'
+            platformId:
+              type: string
+              examples:
+                - Steam
+                - XBL
+              description: Gaming platform the ID references
+            userId:
+              type: string
+              examples:
+                - '76561198021925107'
+              description: Unique ID of the user within the given gaming platform
+          required:
+            - combinedString
+            - platformId
+            - userId
+          description: User ID
+        - type: 'null'
+
 
   responses:
@@ -126,3 +157,2 @@
 
 paths:
-  allOf:
Index: TFP-WebServer/WebServer/src/WebAPI/OpenApiHelpers.cs
===================================================================
--- TFP-WebServer/WebServer/src/WebAPI/OpenApiHelpers.cs	(revision 459)
+++ TFP-WebServer/WebServer/src/WebAPI/OpenApiHelpers.cs	(revision 460)
@@ -3,4 +3,5 @@
 using System.Reflection;
 using System.Text;
+using System.Text.RegularExpressions;
 
 namespace Webserver.WebAPI {
@@ -12,5 +13,15 @@
 		private const string masterDocRefLineEnd = "#/paths";
 
-		private readonly Dictionary<string, string> specs = new CaseInsensitiveStringDictionary<string> ();
+		private struct OpenApiSpec {
+			public readonly List<string> ExportedPaths;
+			public readonly string Spec;
+
+			public OpenApiSpec (string _spec, List<string> _exportedPaths = null) {
+				ExportedPaths = _exportedPaths;
+				Spec = _spec;
+			}
+		}
+
+		private readonly Dictionary<string, OpenApiSpec> specs = new CaseInsensitiveStringDictionary<OpenApiSpec> ();
 
 		public OpenApiHelpers () {
@@ -30,5 +41,5 @@
 			}
 
-			specs.Add (masterDocName, specText);
+			specs.Add (masterDocName, new OpenApiSpec(specText));
 			Log.Out ($"[Web] Loaded main OpenAPI spec");
 		}
@@ -41,15 +52,149 @@
 			StringBuilder sb = new StringBuilder (mainSpec);
 			
-			foreach ((string apiSpecName, _) in specs) {
+			foreach ((string apiSpecName, OpenApiSpec spec) in specs) {
 				if (apiSpecName.Equals (masterDocName)) {
 					continue;
 				}
 
-				sb.AppendLine ($"{masterDocRefLineBegin}./{apiSpecName}{masterDocRefLineEnd}");
-			}
-
-			specs[masterDocName] = sb.ToString ();
+				if ((spec.ExportedPaths?.Count ?? 0) < 1) {
+					continue;
+				}
+
+				foreach (string exportedPath in spec.ExportedPaths) {
+					writePath (sb, apiSpecName, exportedPath);
+				}
+			}
+
+			specs[masterDocName] = new OpenApiSpec(sb.ToString ());
 			
 			Log.Out ("[Web] OpenAPI preparation done");
+		}
+
+		private void writePath (StringBuilder _sb, string _apiSpecName, string _exportedPath) {
+			_sb.AppendLine ($"  {_exportedPath}:");
+			_sb.Append ($"    $ref: './{_apiSpecName}#/paths/");
+
+			for (int i = 0; i < _exportedPath.Length; i++) {
+				char c = _exportedPath[i];
+
+				switch (c) {
+					// JSON string escaped characters
+					case '"':
+						_sb.Append ("\\\"");
+						break;
+					case '\\':
+						_sb.Append ("\\\\");
+						break;
+					case '\b':
+						_sb.Append ("\\b");
+						break;
+					case '\f':
+						_sb.Append ("\\f");
+						break;
+					case '\n':
+						_sb.Append ("\\n");
+						break;
+					case '\r':
+						_sb.Append ("\\r");
+						break;
+					case '\t':
+						_sb.Append ("\\t");
+						break;
+					case (char)0x00:
+						_sb.Append ("\\u0000");
+						break;
+					case (char)0x01:
+						_sb.Append ("\\u0001");
+						break;
+					case (char)0x02:
+						_sb.Append ("\\u0002");
+						break;
+					case (char)0x03:
+						_sb.Append ("\\u0003");
+						break;
+					case (char)0x04:
+						_sb.Append ("\\u0004");
+						break;
+					case (char)0x05:
+						_sb.Append ("\\u0005");
+						break;
+					case (char)0x06:
+						_sb.Append ("\\u0006");
+						break;
+					case (char)0x07:
+						_sb.Append ("\\u0007");
+						break;
+					case (char)0x0b:
+						_sb.Append ("\\u000b");
+						break;
+					case (char)0x0e:
+						_sb.Append ("\\u000e");
+						break;
+					case (char)0x0f:
+						_sb.Append ("\\u000f");
+						break;
+					case (char)0x10:
+						_sb.Append ("\\u0010");
+						break;
+					case (char)0x11:
+						_sb.Append ("\\u0011");
+						break;
+					case (char)0x12:
+						_sb.Append ("\\u0012");
+						break;
+					case (char)0x13:
+						_sb.Append ("\\u0013");
+						break;
+					case (char)0x14:
+						_sb.Append ("\\u0014");
+						break;
+					case (char)0x15:
+						_sb.Append ("\\u0015");
+						break;
+					case (char)0x16:
+						_sb.Append ("\\u0016");
+						break;
+					case (char)0x17:
+						_sb.Append ("\\u0017");
+						break;
+					case (char)0x18:
+						_sb.Append ("\\u0018");
+						break;
+					case (char)0x19:
+						_sb.Append ("\\u0019");
+						break;
+					case (char)0x1a:
+						_sb.Append ("\\u001a");
+						break;
+					case (char)0x1b:
+						_sb.Append ("\\u001b");
+						break;
+					case (char)0x1c:
+						_sb.Append ("\\u001c");
+						break;
+					case (char)0x1d:
+						_sb.Append ("\\u001d");
+						break;
+					case (char)0x1e:
+						_sb.Append ("\\u001e");
+						break;
+					case (char)0x1f:
+						_sb.Append ("\\u001f");
+						break;
+					// JSON Pointer specific
+					case '/':
+						_sb.Append ("~1");
+						break;
+					case '~':
+						_sb.Append ("~0");
+						break;
+					// Non escaped characters
+					default:
+						_sb.Append (c);
+						break;
+				}
+			}
+			
+			_sb.AppendLine ("'");
 		}
 
@@ -65,5 +210,34 @@
 
 			Log.Out ($"[Web] Loaded OpenAPI spec for '{apiName}'");
-			specs.Add (apiSpecName, specText);
+			OpenApiSpec spec = new OpenApiSpec (specText, findExportedPaths (specText));
+			specs.Add (apiSpecName, spec);
+		}
+
+		private static readonly Regex pathMatcher = new Regex ("^\\s{1,2}(/\\S+):.*$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
+		private List<string> findExportedPaths (string _spec) {
+			List<string> result = new List<string> ();
+
+			using TextReader tr = new StringReader (_spec);
+
+			string line;
+			bool inPaths = false;
+			while ((line = tr.ReadLine ()) != null) {
+				if (!inPaths) {
+					if (line.StartsWith ("paths:")) {
+						inPaths = true;
+					}
+				} else {
+					Match match = pathMatcher.Match (line);
+					if (!match.Success) {
+						continue;
+					}
+
+					string path = match.Groups [1].Value;
+					Log.Out ($"[Web]   Exports: {path}");
+					result.Add (path);
+				}
+			}
+
+			return result;
 		}
 
@@ -73,5 +247,11 @@
 			}
 
-			return specs.TryGetValue (_name, out _specText);
+			if (!specs.TryGetValue (_name, out OpenApiSpec spec)) {
+				_specText = null;
+				return false;
+			}
+
+			_specText = spec.Spec;
+			return true;
 		}
 	}
Index: TFP-WebServer/WebServer/webroot/rapidoc.html
===================================================================
--- TFP-WebServer/WebServer/webroot/rapidoc.html	(revision 459)
+++ TFP-WebServer/WebServer/webroot/rapidoc.html	(revision 460)
@@ -7,5 +7,5 @@
   </head>
   <body>
-    <rapi-doc spec-url="/api/openapi/openapi.yaml" render-style="focused" show-header="false" show-method-in-nav-bar="as-colored-block" > </rapi-doc>
+    <rapi-doc spec-url="/api/openapi/openapi.yaml" render-style="focused" show-header="false" show-method-in-nav-bar="as-colored-block" sort-tags="true" schema-description-expanded="true" > </rapi-doc>
   </body>
 </html>
