Index: binary-improvements2/WebServer/src/Permissions/AdminWebModules.cs
===================================================================
--- binary-improvements2/WebServer/src/Permissions/AdminWebModules.cs	(revision 417)
+++ binary-improvements2/WebServer/src/Permissions/AdminWebModules.cs	(revision 418)
@@ -41,5 +41,5 @@
 
 		public void AddModule (string _module, int _permissionLevel) {
-			WebModule p = new WebModule (_module, _permissionLevel);
+			WebModule p = new WebModule (_module, _permissionLevel, false);
 			lock (this) {
 				allModulesList.Clear ();
@@ -84,8 +84,10 @@
 			public readonly string Name;
 			public readonly int PermissionLevel;
+			public readonly bool IsDefault;
 
-			public WebModule (string _name, int _permissionLevel) {
+			public WebModule (string _name, int _permissionLevel, bool _isDefault) {
 				Name = _name;
 				PermissionLevel = _permissionLevel;
+				IsDefault = _isDefault;
 			}
 			
@@ -116,5 +118,5 @@
 				}
 				
-				_result = new WebModule (name, permissionLevel);
+				_result = new WebModule (name, permissionLevel, false);
 				return true;
 			}
@@ -139,5 +141,5 @@
 			}
 
-			WebModule p = new WebModule (_module, _defaultPermission);
+			WebModule p = new WebModule (_module, _defaultPermission, true);
 
 			lock (this) {
@@ -158,11 +160,15 @@
 
 		public bool ModuleAllowedWithLevel (string _module, int _level) {
-			WebModule permInfo = GetModule (_module);
+			WebModule permInfo = GetModule (_module)!.Value;
 			return permInfo.PermissionLevel >= _level;
 		}
 
-		public WebModule GetModule (string _module) {
+		public WebModule? GetModule (string _module, bool _returnDefaults = true) {
 			if (modules.TryGetValue (_module, out WebModule result)) {
 				return result;
+			}
+
+			if (!_returnDefaults) {
+				return null;
 			}
 
@@ -170,5 +176,5 @@
 		}
 
-		private readonly WebModule defaultModulePermission = new WebModule ("", 0);
+		private readonly WebModule defaultModulePermission = new WebModule ("", 0, true);
 		
 #endregion
Index: binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs
===================================================================
--- binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs	(revision 417)
+++ binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs	(revision 418)
@@ -3,5 +3,4 @@
 using System.Net;
 using System.Reflection;
-using Webserver.Permissions;
 using Webserver.WebAPI;
 
@@ -47,5 +46,4 @@
 		private void addApi (AbsWebAPI _api) {
 			apis.Add (_api.Name, _api);
-			AdminWebModules.Instance.AddKnownModule ($"webapi.{_api.Name}", _api.DefaultPermissionLevel ());
 		}
 
@@ -71,5 +69,7 @@
 			}
 
-			if (!IsAuthorizedForApi (apiName, _context.PermissionLevel)) {
+			_context.RequestPath = subPath;
+
+			if (!api.Authorized (_context)) {
 				_context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
 				if (_context.Connection != null) {
@@ -79,6 +79,4 @@
 				return;
 			}
-
-			_context.RequestPath = subPath;
 
 			try {
@@ -92,8 +90,4 @@
 			}
 		}
-
-		private bool IsAuthorizedForApi (string _apiName, int _permissionLevel) {
-			return AdminWebModules.Instance.ModuleAllowedWithLevel ($"webapi.{_apiName}", _permissionLevel);
-		}
 	}
 }
Index: binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs
===================================================================
--- binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 417)
+++ binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 418)
@@ -4,4 +4,5 @@
 using System.Net;
 using Utf8Json;
+using Webserver.Permissions;
 
 namespace Webserver.WebAPI {
@@ -9,8 +10,25 @@
 		private static readonly UnityEngine.Profiling.CustomSampler jsonDeserializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Deserialize");
 
+		protected readonly string[] CachedPerMethodModuleNames = new string[(int)ERequestMethod.Count];
+
 		protected AbsRestApi (string _name = null) : this(null, _name) {
 		}
 
 		protected AbsRestApi (Web _parentWeb, string _name = null) : base(_parentWeb, _name) {
+		}
+
+		protected override void RegisterPermissions () {
+			base.RegisterPermissions ();
+			
+			for (int i = 0; i < (int)ERequestMethod.Count; i++) {
+				ERequestMethod method = (ERequestMethod)i;
+
+				if (method is not (ERequestMethod.GET or ERequestMethod.PUT or ERequestMethod.POST or ERequestMethod.DELETE)) {
+					continue;
+				}
+
+				CachedPerMethodModuleNames [i] = $"webapi.{Name}:{method.ToStringCached ()}";
+				AdminWebModules.Instance.AddKnownModule (CachedPerMethodModuleNames [i], DefaultMethodPermissionLevel (method));
+			}
 		}
 
@@ -44,6 +62,6 @@
 
 			try {
-				switch (_context.Request.HttpMethod) {
-					case "GET":
+				switch (_context.Method) {
+					case ERequestMethod.GET:
 						if (inputJson != null) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY");
@@ -53,5 +71,5 @@
 						HandleRestGet (_context);
 						return;
-					case "POST":
+					case ERequestMethod.POST:
 						if (!string.IsNullOrEmpty (_context.RequestPath)) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID");
@@ -66,5 +84,5 @@
 						HandleRestPost (_context, inputJson, jsonInputData);
 						return;
-					case "PUT":
+					case ERequestMethod.PUT:
 						if (string.IsNullOrEmpty (_context.RequestPath)) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID");
@@ -79,5 +97,5 @@
 						HandleRestPut (_context, inputJson, jsonInputData);
 						return;
-					case "DELETE":
+					case ERequestMethod.DELETE:
 						if (string.IsNullOrEmpty (_context.RequestPath)) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID");
@@ -101,4 +119,61 @@
 		}
 
+		protected virtual void HandleRestGet (RequestContext _context) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
+		}
+
+		protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
+		}
+
+		protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
+		}
+
+		protected virtual void HandleRestDelete (RequestContext _context) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
+		}
+
+		public override bool Authorized (RequestContext _context) {
+			return ActiveMethodPermissionLevel (_context.Method) >= _context.PermissionLevel;
+		}
+
+		/// <summary>
+		/// Define default permission levels per HTTP method
+		/// </summary>
+		/// <param name="_method">HTTP method to return the default value for</param>
+		/// <returns>Default permission level for the given HTTP method. A value of int.MinValue means no per-method default, use per-API default</returns>
+		public virtual int DefaultMethodPermissionLevel (ERequestMethod _method) => int.MinValue;
+
+		public virtual int ActiveMethodPermissionLevel (ERequestMethod _method) {
+			string methodApiModuleName = CachedPerMethodModuleNames [(int)_method];
+
+			if (methodApiModuleName == null) {
+				return 0;
+			}
+
+			AdminWebModules.WebModule? overrideModule = AdminWebModules.Instance.GetModule (methodApiModuleName, false);
+			if (overrideModule.HasValue) {
+				return overrideModule.Value.PermissionLevel;
+			}
+
+			overrideModule = AdminWebModules.Instance.GetModule (CachedApiModuleName, false);
+			if (overrideModule.HasValue) {
+				return overrideModule.Value.PermissionLevel;
+			}
+
+			int defaultMethodPermissionLevel = DefaultMethodPermissionLevel (_method);
+			// ReSharper disable once ConvertIfStatementToReturnStatement
+			if (defaultMethodPermissionLevel != int.MinValue) {
+				return defaultMethodPermissionLevel;
+			}
+
+			return DefaultPermissionLevel ();
+		}
+
+#region Helpers
+
+		protected static readonly byte[] JsonEmptyData;
+		
 		static AbsRestApi () {
 			JsonWriter writer = new JsonWriter ();
@@ -108,25 +183,4 @@
 		}
 
-		protected virtual void HandleRestGet (RequestContext _context) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
-		}
-
-		protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
-		}
-
-		protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
-		}
-
-		protected virtual void HandleRestDelete (RequestContext _context) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
-		}
-
-
-#region Helpers
-
-		protected static readonly byte[] JsonEmptyData;
-		
 		protected static void PrepareEnvelopedResult (out JsonWriter _writer) {
 			WebUtils.PrepareEnvelopedResult (out _writer);
Index: binary-improvements2/WebServer/src/WebAPI/AbsWebAPI.cs
===================================================================
--- binary-improvements2/WebServer/src/WebAPI/AbsWebAPI.cs	(revision 417)
+++ binary-improvements2/WebServer/src/WebAPI/AbsWebAPI.cs	(revision 418)
@@ -1,6 +1,10 @@
+using Webserver.Permissions;
+
 namespace Webserver.WebAPI {
 	public abstract class AbsWebAPI {
 		public readonly string Name;
 		protected readonly Web ParentWeb;
+
+		protected readonly string CachedApiModuleName;
 
 		protected AbsWebAPI (string _name = null) : this(null, _name) {
@@ -10,8 +14,18 @@
 			Name = _name ?? GetType ().Name;
 			ParentWeb = _parentWeb;
+			CachedApiModuleName = $"webapi.{Name}";
+			RegisterPermissions ();
+		}
+
+		protected virtual void RegisterPermissions () {
+			AdminWebModules.Instance.AddKnownModule ($"webapi.{Name}", DefaultPermissionLevel ());
 		}
 
 		public abstract void HandleRequest (RequestContext _context);
 
+		public virtual bool Authorized (RequestContext _context) {
+			return AdminWebModules.Instance.ModuleAllowedWithLevel (CachedApiModuleName, _context.PermissionLevel);
+		}
+
 		public virtual int DefaultPermissionLevel () => 0;
 	}
