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;
 		}
 	}
