diff --git a/CHANGELOG.md b/CHANGELOG.md
index c589892..f2b0e62 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@
 - The `/thumbnail` endpoint supports a new size labeled `tiny` which returns 40x40px images.
 - Persistent data, such as playlists, is now saved in a directory that may be configured with the `--data` CLI option or the `POLARIS_DATA_DIR` environment variable.
 - Removed last.fm integration due to maintenance concerns (abandoned libraries, broken account linking) and mismatch with project goals.
+- Removed `/config` API endpoint.
 
 ### Web client
 
diff --git a/src/server/axum/api.rs b/src/server/axum/api.rs
index 99a681f..e39ca65 100644
--- a/src/server/axum/api.rs
+++ b/src/server/axum/api.rs
@@ -12,7 +12,7 @@ use axum_range::{KnownSize, Ranged};
 use tower_http::{compression::CompressionLayer, CompressionLevel};
 
 use crate::{
-	app::{config, ddns, index, peaks, playlist, scanner, settings, thumbnail, user, vfs, App},
+	app::{ddns, index, peaks, playlist, scanner, settings, thumbnail, user, vfs, App},
 	server::{
 		dto, error::APIError, APIMajorVersion, API_ARRAY_SEPARATOR, API_MAJOR_VERSION,
 		API_MINOR_VERSION,
@@ -28,7 +28,6 @@ pub fn router() -> Router<App> {
 		.route("/initial_setup", get(get_initial_setup))
 		.route("/auth", post(post_auth))
 		// Configuration
-		.route("/config", put(put_config))
 		.route("/settings", get(get_settings))
 		.route("/settings", put(put_settings))
 		.route("/mount_dirs", get(get_mount_dirs))
@@ -101,15 +100,6 @@ async fn get_initial_setup(
 	Ok(Json(initial_setup))
 }
 
-async fn put_config(
-	_admin_rights: AdminRights,
-	State(config_manager): State<config::Manager>,
-	Json(config): Json<dto::Config>,
-) -> Result<(), APIError> {
-	config_manager.apply(&config.into()).await?;
-	Ok(())
-}
-
 async fn get_settings(
 	State(settings_manager): State<settings::Manager>,
 	_admin_rights: AdminRights,
diff --git a/src/server/test.rs b/src/server/test.rs
index c79ae86..8a2fe3e 100644
--- a/src/server/test.rs
+++ b/src/server/test.rs
@@ -65,28 +65,41 @@ pub trait TestService {
 	}
 
 	async fn complete_initial_setup(&mut self) {
-		let configuration = dto::Config {
-			users: Some(vec![
-				dto::NewUser {
-					name: TEST_USERNAME_ADMIN.into(),
-					password: TEST_PASSWORD_ADMIN.into(),
-					admin: true,
-				},
-				dto::NewUser {
-					name: TEST_USERNAME.into(),
-					password: TEST_PASSWORD.into(),
-					admin: false,
-				},
-			]),
-			mount_dirs: Some(vec![dto::MountDir {
+		assert_eq!(
+			self.fetch(&protocol::put_mount_dirs(vec![dto::MountDir {
 				name: TEST_MOUNT_NAME.into(),
 				source: TEST_MOUNT_SOURCE.into(),
-			}]),
-			..Default::default()
-		};
-		let request = protocol::apply_config(configuration);
-		let response = self.fetch(&request).await;
-		assert_eq!(response.status(), StatusCode::OK);
+			}]))
+			.await
+			.status(),
+			StatusCode::OK
+		);
+
+		assert_eq!(
+			self.fetch(&protocol::create_user(dto::NewUser {
+				name: TEST_USERNAME_ADMIN.into(),
+				password: TEST_PASSWORD_ADMIN.into(),
+				admin: true,
+			}))
+			.await
+			.status(),
+			StatusCode::OK
+		);
+
+		self.login_admin().await;
+
+		assert_eq!(
+			self.fetch(&protocol::create_user(dto::NewUser {
+				name: TEST_USERNAME.into(),
+				password: TEST_PASSWORD.into(),
+				admin: false,
+			}))
+			.await
+			.status(),
+			StatusCode::OK
+		);
+
+		self.logout().await;
 	}
 
 	async fn login_internal(&mut self, username: &str, password: &str) {
diff --git a/src/server/test/protocol.rs b/src/server/test/protocol.rs
index 20a892d..d08d2ef 100644
--- a/src/server/test/protocol.rs
+++ b/src/server/test/protocol.rs
@@ -68,11 +68,11 @@ pub fn login(username: &str, password: &str) -> Request<dto::Credentials> {
 		.unwrap()
 }
 
-pub fn apply_config(config: dto::Config) -> Request<dto::Config> {
+pub fn put_mount_dirs(dirs: Vec<dto::MountDir>) -> Request<Vec<dto::MountDir>> {
 	Request::builder()
 		.method(Method::PUT)
-		.uri("/api/config")
-		.body(config)
+		.uri("/api/mount_dirs")
+		.body(dirs)
 		.unwrap()
 }