diff --git a/common/src/main/java/de/ozgcloud/eingang/Application.java b/common/src/main/java/de/ozgcloud/eingang/Application.java
index f03fc325e5c9db727db8020425efdd1e7d2ea0f3..b4ea3d5e2681ff558140f3d8b26a298118f7d87b 100644
--- a/common/src/main/java/de/ozgcloud/eingang/Application.java
+++ b/common/src/main/java/de/ozgcloud/eingang/Application.java
@@ -33,6 +33,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
 @EnableScheduling
 public class Application {
 
+	public static final String ZUFI_MANAGER_GRPC_CLIENT = "zufi-manager";
+
 	public static void main(String[] args) {
 		TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
 		SpringApplication.run(Application.class, args);
diff --git a/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java b/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java
index 8a2f3c291eb730fa9a0f93b6291bdd2e15dc9555..1024f573ab906e15942513d187b3afda11c8af1e 100644
--- a/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java
+++ b/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java
@@ -21,6 +21,7 @@ import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.util.ReflectionTestUtils;
 
 import de.ozgcloud.common.test.TestUtils;
+import de.ozgcloud.eingang.router.ManagableStub;
 import de.ozgcloud.eingang.router.VorgangManagerServerResolver;
 import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
 import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileRequest;
@@ -49,17 +50,23 @@ public class FormsolutionsITCase {
 	@Mock
 	private VorgangServiceBlockingStub blockingStub;
 	@Mock
+	private ManagableStub<VorgangServiceBlockingStub> managableVorgangServiceBlockingStub;
+	@Mock
 	private BinaryFileServiceStub fileStub;
 	@Mock
+	private ManagableStub<BinaryFileServiceStub> managableBinaryFileStub;
+	@Mock
 	private CallStreamObserver<GrpcUploadBinaryFileRequest> fileStreamObserver;
 
 	@BeforeEach
 	void initVorgangManagerResolver() {
-		when(resolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(any())).thenReturn(blockingStub);
-		when(resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(any())).thenReturn(fileStub);
-		
+		when(resolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(any())).thenReturn(managableVorgangServiceBlockingStub);
+		when(managableVorgangServiceBlockingStub.get()).thenReturn(blockingStub);
+		when(resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(any())).thenReturn(managableBinaryFileStub);
+		when(managableBinaryFileStub.get()).thenReturn(fileStub);
+
 		Channel mockChannel = mock(Channel.class);
-		when(blockingStub.getChannel()).thenReturn(mockChannel );
+		when(blockingStub.getChannel()).thenReturn(mockChannel);
 		when(blockingStub.startCreation(any())).thenReturn(GrpcCreateVorgangResponse.newBuilder().setVorgangId("42").build());
 
 		when(fileStub.uploadBinaryFileAsStream(any())).thenReturn(fileStreamObserver);
diff --git a/pom.xml b/pom.xml
index f171a23df4dd53f4266bb0db5a7c224a560546c9..fc1c3a6522eee55b25c01c4eebb1fd8b8e347e06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,6 +56,7 @@
 
 	<properties>
 		<vorgang-manager.version>2.10.0</vorgang-manager.version>
+		<zufi-manager.version>1.2.0-SNAPSHOT</zufi-manager.version>
 
 		<jsoup.version>1.14.3</jsoup.version>
 		<xmlschema.version>2.3.0</xmlschema.version>
@@ -100,6 +101,11 @@
 				<artifactId>vorgang-manager-utils</artifactId>
 				<version>${vorgang-manager.version}</version>
 			</dependency>
+			<dependency>
+				<groupId>de.ozgcloud.zufi</groupId>
+				<artifactId>zufi-manager-interface</artifactId>
+				<version>${zufi-manager.version}</version>
+			</dependency>
 
 			<dependency>
 				<groupId>org.jsoup</groupId>
diff --git a/router/pom.xml b/router/pom.xml
index d8c7fdd6b4307c52a640f0c403e9cfae05e1e78c..bbd0a1666fdd99839c708b2622668fa50910ea08 100644
--- a/router/pom.xml
+++ b/router/pom.xml
@@ -50,6 +50,10 @@
 			<groupId>de.ozgcloud.vorgang</groupId>
 			<artifactId>vorgang-manager-utils</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>de.ozgcloud.zufi</groupId>
+			<artifactId>zufi-manager-interface</artifactId>
+		</dependency>
 
 		<!-- spring -->
 		<dependency>
diff --git a/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheit.java b/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheit.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b02d54577a0066a14537c931e37eefeecd36591
--- /dev/null
+++ b/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheit.java
@@ -0,0 +1,16 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@Builder
+class OrganisationsEinheit {
+
+	private String id;
+	private String name;
+	private String synonyme;
+	private String vorgangManagerAddress;
+}
\ No newline at end of file
diff --git a/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitMapper.java b/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad048c2cdbca5a22ab34c67a678abc50642b4764
--- /dev/null
+++ b/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitMapper.java
@@ -0,0 +1,11 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import org.mapstruct.Mapper;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit;
+
+@Mapper
+interface OrganisationsEinheitMapper {
+
+	OrganisationsEinheit fromGrpc(GrpcOrganisationsEinheit organisationsEinheit);
+}
\ No newline at end of file
diff --git a/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitRemoteService.java b/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitRemoteService.java
new file mode 100644
index 0000000000000000000000000000000000000000..d7ec3990817a1649dd2e10c08fd5fd021daa24ea
--- /dev/null
+++ b/router/src/main/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitRemoteService.java
@@ -0,0 +1,24 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import de.ozgcloud.eingang.Application;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetRequest;
+import de.ozgcloud.zufi.grpc.organisationseinheit.OrganisationsEinheitServiceGrpc.OrganisationsEinheitServiceBlockingStub;
+import net.devh.boot.grpc.client.inject.GrpcClient;
+
+@Service
+class OrganisationsEinheitRemoteService {
+
+	@GrpcClient(Application.ZUFI_MANAGER_GRPC_CLIENT)
+	private OrganisationsEinheitServiceBlockingStub serviceStub;
+	@Autowired
+	private OrganisationsEinheitMapper mapper;
+
+	public OrganisationsEinheit getById(String id) {
+		var response = serviceStub.getById(GrpcOrganisationsEinheitGetRequest.newBuilder().setId(id).build());
+
+		return mapper.fromGrpc(response.getOrganisationsEinheit());
+	}
+}
diff --git a/router/src/main/java/de/ozgcloud/eingang/common/zufi/ZufiService.java b/router/src/main/java/de/ozgcloud/eingang/common/zufi/ZufiService.java
new file mode 100644
index 0000000000000000000000000000000000000000..7992033c7b2a7bea338bc8e5a9a68014839cc66d
--- /dev/null
+++ b/router/src/main/java/de/ozgcloud/eingang/common/zufi/ZufiService.java
@@ -0,0 +1,16 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import org.springframework.stereotype.Service;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Service
+public class ZufiService {
+
+	private final OrganisationsEinheitRemoteService remoteService;
+
+	public String getVorgangManagerUrl(String organisationsEinheitId) {
+		return remoteService.getById(organisationsEinheitId).getVorgangManagerAddress();
+	}
+}
\ No newline at end of file
diff --git a/router/src/main/java/de/ozgcloud/eingang/router/ClosableStub.java b/router/src/main/java/de/ozgcloud/eingang/router/ClosableStub.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba15eaff4ce83299153a6a766d38c23f42deadc4
--- /dev/null
+++ b/router/src/main/java/de/ozgcloud/eingang/router/ClosableStub.java
@@ -0,0 +1,44 @@
+package de.ozgcloud.eingang.router;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
+import io.grpc.ManagedChannel;
+import io.grpc.stub.AbstractStub;
+import lombok.Builder;
+
+@Builder
+class ClosableStub<T extends AbstractStub<?>> implements ManagableStub<T> {
+
+	private static final int SHUTDOWN_TIME_IN_SEC = 3;
+
+	private T stub;
+	private ManagedChannel channel;
+
+	@Override
+	public T get() {
+		return stub;
+	}
+
+	public void close() {
+		if (Objects.nonNull(stub)) {
+			shutdownChannel();
+			stub = null;
+		}
+	}
+
+	private void shutdownChannel() {
+		try {
+			channel.shutdown().awaitTermination(ClosableStub.SHUTDOWN_TIME_IN_SEC, TimeUnit.SECONDS);
+		} catch (InterruptedException e) {
+			Thread.currentThread().interrupt();
+			throw new TechnicalException("Error shutting down grpc channel.", e);
+		}
+	}
+
+	@Override
+	public boolean isShutdownable() {
+		return true;
+	}
+}
\ No newline at end of file
diff --git a/router/src/main/java/de/ozgcloud/eingang/router/ConsistentStub.java b/router/src/main/java/de/ozgcloud/eingang/router/ConsistentStub.java
new file mode 100644
index 0000000000000000000000000000000000000000..25c543504781b57791c2877b016b09e1d688ad9e
--- /dev/null
+++ b/router/src/main/java/de/ozgcloud/eingang/router/ConsistentStub.java
@@ -0,0 +1,20 @@
+package de.ozgcloud.eingang.router;
+
+import io.grpc.stub.AbstractStub;
+import lombok.Builder;
+
+@Builder
+class ConsistentStub<T extends AbstractStub<?>> implements ManagableStub<T> {
+
+	private T stub;
+
+	@Override
+	public T get() {
+		return stub;
+	}
+
+	@Override
+	public boolean isShutdownable() {
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/router/src/main/java/de/ozgcloud/eingang/router/GrpcClientsProperties.java b/router/src/main/java/de/ozgcloud/eingang/router/GrpcClientsProperties.java
index 3f308dd3d9173e02b78ec94966f615ea9398bd98..376bdc14c6f6a70064f78e64e860b3642404c3e7 100644
--- a/router/src/main/java/de/ozgcloud/eingang/router/GrpcClientsProperties.java
+++ b/router/src/main/java/de/ozgcloud/eingang/router/GrpcClientsProperties.java
@@ -48,7 +48,7 @@ public class GrpcClientsProperties {
 	static class ClientProperty {
 		@NotEmpty
 		private String address;
-		private String negotationType = "TLS";
+		private String negotiationType = "TLS";
 	}
 
 }
diff --git a/router/src/main/java/de/ozgcloud/eingang/router/ManagableStub.java b/router/src/main/java/de/ozgcloud/eingang/router/ManagableStub.java
new file mode 100644
index 0000000000000000000000000000000000000000..bce38696c16e1ac7ccf385b21deb6e1e0c1548f0
--- /dev/null
+++ b/router/src/main/java/de/ozgcloud/eingang/router/ManagableStub.java
@@ -0,0 +1,8 @@
+package de.ozgcloud.eingang.router;
+
+public interface ManagableStub<T> {
+
+	T get();
+
+	boolean isShutdownable();
+}
\ No newline at end of file
diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerListProperties.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerListProperties.java
index 8ca85a7d7f35009e149d6a2e77f382f6c841df19..7d615b5dfe7d4fba58e2bb6c1b1d8d38fe56f2f5 100644
--- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerListProperties.java
+++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerListProperties.java
@@ -46,6 +46,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.validation.annotation.Validated;
 
+import de.ozgcloud.eingang.Application;
 import de.ozgcloud.eingang.router.VorgangManagerListProperties.VorgangManagerListPropertiesConstraint;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
@@ -64,7 +65,7 @@ class VorgangManagerListProperties {
 	}
 
 	enum RoutingStrategy {
-		MULTI, SINGLE
+		MULTI, SINGLE, ZUFI
 	}
 
 	@Autowired(required = false)
@@ -92,20 +93,28 @@ class VorgangManagerListProperties {
 	}
 
 	@AllArgsConstructor
-	public static class VorgangManagerListPropertiesValidator implements ConstraintValidator<VorgangManagerListPropertiesConstraint, VorgangManagerListProperties> {
+	public static class VorgangManagerListPropertiesValidator
+			implements ConstraintValidator<VorgangManagerListPropertiesConstraint, VorgangManagerListProperties> {
 
-		private static final Predicate<VorgangManagerListProperties> IS_SINGLE_ROUTING = props -> props.getRoutingStrategy() == RoutingStrategy.SINGLE;
+		private static final Predicate<VorgangManagerListProperties> IS_SINGLE_ROUTING = props -> props
+				.getRoutingStrategy() == RoutingStrategy.SINGLE;
 		private static final Predicate<VorgangManagerListProperties> HAS_TARGET_NAME = props -> props.getTargetVorgangManagerName().isPresent();
 
 		private static final Predicate<VorgangManagerListProperties> IS_MULTI_ROUTING = props -> props.getRoutingStrategy() == RoutingStrategy.MULTI;
 		private static final Predicate<VorgangManagerListProperties> HAS_FALLBACK_STRATEGY = props -> Objects.nonNull(props.getFallbackStrategy());
 
+		private static final Predicate<VorgangManagerListProperties> IS_ZUFI_ROUTING = props -> props.getRoutingStrategy() == RoutingStrategy.ZUFI;
+
 		private static final Predicate<VorgangManagerListProperties> IS_FALLBACK_TO_FUNDSTELLE = props -> props.getFallbackStrategy()
 				.map(strategy -> strategy == FallbackStrategy.FUNDSTELLE).orElse(false);
 		private static final Predicate<VorgangManagerListProperties> HAS_FUNDSTELLE = props -> props.getFundstelleVorgangManagerName().isPresent();
 
 		@Override
 		public boolean isValid(VorgangManagerListProperties value, ConstraintValidatorContext context) {
+			return isVorgangManagerRoutingValid(value) || isZufiManagerRoutingValid(value);
+		}
+
+		private boolean isVorgangManagerRoutingValid(VorgangManagerListProperties value) {
 			return IS_SINGLE_ROUTING.and(HAS_TARGET_NAME)
 					.or(IS_MULTI_ROUTING.and(HAS_FALLBACK_STRATEGY))
 					.and(IS_FALLBACK_TO_FUNDSTELLE.negate().or(HAS_FUNDSTELLE))
@@ -113,14 +122,26 @@ class VorgangManagerListProperties {
 					.test(value);
 		}
 
+		private boolean isZufiManagerRoutingValid(VorgangManagerListProperties value) {
+			return IS_ZUFI_ROUTING.and(this::isZufiConfigured).test(value);
+		}
+
 		private boolean hasAllVorgangManagersConfigured(VorgangManagerListProperties props) {
 			var clientNames = props.getClientProperties()
 					.map(ps -> ps.getClient())
 					.map(Map::keySet)
 					.orElse(Collections.emptySet());
 
-			return props.getOrganisationseinheiten().values().stream().map(organisationseinheitName -> clientNames.contains("vorgang-manager-" + organisationseinheitName))
+			return props.getOrganisationseinheiten().values().stream()
+					.map(organisationseinheitName -> clientNames.contains("vorgang-manager-" + organisationseinheitName))
 					.collect(Collectors.reducing(true, Boolean::logicalAnd));
 		}
+
+		private boolean isZufiConfigured(VorgangManagerListProperties props) {
+			return props.getClientProperties()
+					.map(ps -> ps.getClient())
+					.map(client -> client.get(Application.ZUFI_MANAGER_GRPC_CLIENT))
+					.isPresent();
+		}
 	}
 }
diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java
index a227052a1c5c58ed3baf19d946243b91b20c3ef6..6108c9ceb3d999e7349e1a7e588b69e1bb693abd 100644
--- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java
+++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java
@@ -33,6 +33,8 @@ import jakarta.validation.Valid;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import de.ozgcloud.common.errorhandling.TechnicalException;
+import de.ozgcloud.eingang.common.zufi.ZufiService;
 import de.ozgcloud.eingang.router.VorgangManagerListProperties.FallbackStrategy;
 import de.ozgcloud.eingang.router.VorgangManagerListProperties.RoutingStrategy;
 import de.ozgcloud.eingang.router.errorhandling.AdapterConfigurationException;
@@ -40,6 +42,8 @@ import de.ozgcloud.eingang.router.errorhandling.UnknownOrganisationseinheitExcep
 import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
 import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub;
 import io.grpc.Channel;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
 import io.grpc.stub.AbstractStub;
 import lombok.NonNull;
 import lombok.extern.log4j.Log4j2;
@@ -47,8 +51,8 @@ import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
 import net.devh.boot.grpc.client.inject.StubTransformer;
 import net.devh.boot.grpc.client.stubfactory.StubFactory;
 
-@Component
 @Log4j2
+@Component
 public class VorgangManagerServerResolver {
 
 	static final String CHANNEL_NAME_PREFIX = "vorgang-manager-";
@@ -64,13 +68,16 @@ public class VorgangManagerServerResolver {
 	@Autowired(required = false)
 	private Collection<StubTransformer> stubTransformers = Collections.emptyList();
 
-	private StubFactory vorgangStubFactory;
-	private StubFactory binaryFileAsynStubFactory;
+	private StubFactory vorgangBlockingStubFactory;
+	private StubFactory binaryFileStubFactory;
+
+	@Autowired
+	private ZufiService zufiService;
 
 	@PostConstruct
 	void findApplicableStubFactories() {
-		vorgangStubFactory = findStubFactory(VorgangServiceBlockingStub.class);
-		binaryFileAsynStubFactory = findStubFactory(BinaryFileServiceStub.class);
+		vorgangBlockingStubFactory = findStubFactory(VorgangServiceBlockingStub.class);
+		binaryFileStubFactory = findStubFactory(BinaryFileServiceStub.class);
 	}
 
 	StubFactory findStubFactory(Class<? extends AbstractStub<?>> stubClass) {
@@ -79,38 +86,77 @@ public class VorgangManagerServerResolver {
 				.findFirst().orElseThrow(() -> new AdapterConfigurationException("Cannot find Stub-Factory for GRPC-" + stubClass));
 	}
 
-	public VorgangServiceBlockingStub resolveVorgangServiceBlockingStubByOrganisationseinheitenId(Optional<String> organisationsEinheitId) {
-		return (VorgangServiceBlockingStub) createStub(organisationsEinheitId, vorgangStubFactory, VorgangServiceBlockingStub.class);
+	public ManagableStub<VorgangServiceBlockingStub> resolveVorgangServiceBlockingStubByOrganisationseinheitenId(
+			Optional<String> organisationsEinheitId) {
+		return createStub(organisationsEinheitId, vorgangBlockingStubFactory, VorgangServiceBlockingStub.class);
 	}
 
-	public BinaryFileServiceStub resolveBinaryFileServiceStubByOrganisationsEinheitId(Optional<String> organisationsEinheitId) {
-		return (BinaryFileServiceStub) createStub(organisationsEinheitId, binaryFileAsynStubFactory, BinaryFileServiceStub.class);
+	public ManagableStub<BinaryFileServiceStub> resolveBinaryFileServiceStubByOrganisationsEinheitId(Optional<String> organisationsEinheitId) {
+		return createStub(organisationsEinheitId, binaryFileStubFactory, BinaryFileServiceStub.class);
 	}
 
-	AbstractStub<?> createStub(Optional<String> organisationsEinheitId, StubFactory stubFactory, Class<? extends AbstractStub<?>> stubClass) {// NOSONAR
-		var channelName = getChannelName(organisationsEinheitId);
-		var stub = stubFactory.createStub(stubClass, createChannelByName(channelName));
+	<T extends AbstractStub<T>> ManagableStub<T> createStub(Optional<String> organisationsEinheitId, StubFactory stubFactory, Class<T> stubClass) {
+		if (isZufiStrategy()) {
+			return createCloseableStub(organisationsEinheitId, stubFactory, stubClass);
+		}
+		return createStubByConfiguredChannels(organisationsEinheitId, stubFactory, stubClass);
+	}
 
-		return applyStubTransformers(stub, channelName);
+	private boolean isZufiStrategy() {
+		return properties.getRoutingStrategy() == RoutingStrategy.ZUFI;
 	}
 
-	AbstractStub<?> applyStubTransformers(AbstractStub<?> stub, String channelName) { // NOSONAR wildcard given by StubTransformer
-		for (var transformer : stubTransformers) {
-			stub = transformer.transform(channelName, stub);
+	<T extends AbstractStub<T>> ManagableStub<T> createCloseableStub(Optional<String> organisationsEinheitId, StubFactory stubFactory,
+			Class<T> stubClass) {
+		var channelName = getVorgangManagerAddress(organisationsEinheitId);
+		var channel = createChannel(channelName);
+		var stub = stubFactory.createStub(stubClass, channel);
+		stub = applyStubTransformers(stub, channelName);
+		return buildClosableStub(stub, channel);
+	}
+
+	@SuppressWarnings("unchecked")
+	private <T extends AbstractStub<?>> ClosableStub<T> buildClosableStub(AbstractStub<?> stub, ManagedChannel channel) {
+		return ClosableStub.<T>builder().stub((T) stub).channel(channel).build();
+	}
+
+	ManagedChannel createChannel(String channelName) {
+		return ManagedChannelBuilder.forTarget(channelName).usePlaintext().build();
+	}
+
+	String getVorgangManagerAddress(Optional<String> organisationsEinheitId) {
+		if (organisationsEinheitId.isEmpty()) {
+			throw new TechnicalException("No organisationsEinheitId exists, can not build connection to vorgang-manager.");
 		}
-		return stub;
+		return zufiService.getVorgangManagerUrl(organisationsEinheitId.get());
+	}
+
+	<T extends AbstractStub<T>> ManagableStub<T> createStubByConfiguredChannels(Optional<String> organisationsEinheitId, StubFactory stubFactory,
+			Class<T> stubClass) {
+		var channelName = getChannelName(organisationsEinheitId);
+		var stub = stubFactory.createStub(stubClass, createChannelByName(channelName));
+		stub = applyStubTransformers(stub, channelName);
+		return buildConsistentStub(stub);
+	}
+
+	@SuppressWarnings("unchecked")
+	private <T extends AbstractStub<?>> ConsistentStub<T> buildConsistentStub(AbstractStub<?> stub) {
+		return ConsistentStub.<T>builder().stub((T) stub).build();
 	}
 
 	String getChannelName(Optional<String> organisationsEinheitId) {
-		Optional<String> target;
+		return getChannelTarget(organisationsEinheitId).map(this::addChannelPrefix).orElseGet(this::getFundstelleChannelName);
+	}
 
-		if (properties.getRoutingStrategy() == RoutingStrategy.SINGLE) {
-			target = properties.getTargetVorgangManagerName();
-		} else {
-			target = organisationsEinheitId.map(properties.getOrganisationseinheiten()::get);
-		}
+	private Optional<String> getChannelTarget(Optional<String> organisationsEinheitId) {
+		return isSingleRoutingStrategy()
+				? properties.getTargetVorgangManagerName()
+				: organisationsEinheitId.map(properties.getOrganisationseinheiten()::get);
 
-		return target.map(this::addChannelPrefix).orElseGet(this::getFundstelleChannelName);
+	}
+
+	private boolean isSingleRoutingStrategy() {
+		return properties.getRoutingStrategy() == RoutingStrategy.SINGLE;
 	}
 
 	private String addChannelPrefix(@NonNull String name) {
@@ -134,4 +180,11 @@ public class VorgangManagerServerResolver {
 	Channel createChannelByName(String name) {
 		return grpcChannelFactory.createChannel(name);
 	}
+
+	AbstractStub<?> applyStubTransformers(AbstractStub<?> stub, String channelName) { // NOSONAR wildcard given by StubTransformer
+		for (var transformer : stubTransformers) {
+			stub = transformer.transform(channelName, stub);
+		}
+		return stub;
+	}
 }
\ No newline at end of file
diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java
index 54ee2075fe8827984a34b0dfec99c4a9cbec410f..e359c1c58d2b85fc2326c74ac848ef4287f5d972 100644
--- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java
+++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java
@@ -67,21 +67,40 @@ public class VorgangRemoteService {
 	private VorgangManagerServerResolver vorgangManagerServerResolver;
 
 	public String createVorgang(FormData formData, GrpcEingang eingang, Optional<String> organisationsEinheitenId) {
-		var vorgangManagerStub = vorgangManagerServerResolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitenId);
-		LOG.info("Connecting to vorgang-manager server " + vorgangManagerStub.getChannel().authority() + "; OrganisationsEinheitId: " + organisationsEinheitenId);
+		var vorgangServiceStub = getVorgangServiceStub(organisationsEinheitenId);
+		var binaryFileServiceStub = getBinaryFileServiceStub(organisationsEinheitenId);
 
-		return createVorgang(formData, eingang, vorgangManagerStub, getBinaryFileServiceStub(organisationsEinheitenId));
+		logConnection(organisationsEinheitenId, vorgangServiceStub.get());
+
+		try {
+			return createVorgang(formData, eingang, vorgangServiceStub.get(), binaryFileServiceStub.get());
+		} finally {
+			finishStubConnections(List.of(vorgangServiceStub, binaryFileServiceStub));
+		}
 	}
 
-	public String createVorgang(FormData formData, GrpcEingang eingang, VorgangServiceBlockingStub remoteStub,
-			BinaryFileServiceStub remoteAsyncStub) {
-		return new VorgangCreator(formData, eingang, remoteStub, remoteAsyncStub).create();
+	void logConnection(Optional<String> organisationsEinheitenId, VorgangServiceBlockingStub vorgangStub) {
+		LOG.info("Connecting to vorgang-manager {}; OrganisationsEinheitId: {}.", vorgangStub.getChannel().authority(),
+				organisationsEinheitenId);
 	}
 
-	private BinaryFileServiceStub getBinaryFileServiceStub(Optional<String> organisationsEinheitenId) {
+	private ManagableStub<VorgangServiceBlockingStub> getVorgangServiceStub(Optional<String> organisationsEinheitenId) {
+		return vorgangManagerServerResolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitenId);
+	}
+
+	private ManagableStub<BinaryFileServiceStub> getBinaryFileServiceStub(Optional<String> organisationsEinheitenId) {
 		return vorgangManagerServerResolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(organisationsEinheitenId);
 	}
 
+	public String createVorgang(FormData formData, GrpcEingang eingang, VorgangServiceBlockingStub vorgangStub,
+			BinaryFileServiceStub binaryFileStub) {
+		return new VorgangCreator(formData, eingang, vorgangStub, binaryFileStub).create();
+	}
+
+	void finishStubConnections(List<ManagableStub<?>> stubs) {
+		stubs.stream().filter(ManagableStub::isShutdownable).map(ClosableStub.class::cast).forEach(ClosableStub::close);
+	}
+
 	@RequiredArgsConstructor
 	public class VorgangCreator {
 
@@ -124,14 +143,17 @@ public class VorgangRemoteService {
 		}
 
 		private IncomingFileGroup uploadAttachment(IncomingFileGroup attachment) {
-			var filesWithId = attachment.getFiles().stream().map(file -> file.toBuilder().id(uploadIncomingFile(file)).build()).toList();
+			var filesWithId = attachment.getFiles().stream().map(this::addIncomingFileId).toList();
 
 			return IncomingFileGroup.builder().name(attachment.getName()).files(filesWithId).build();
 		}
 
 		List<IncomingFile> uploadRepresentations() {
-			return formData.getRepresentations().stream()
-					.map(representation -> representation.toBuilder().id(uploadIncomingFile(representation)).build()).toList();
+			return formData.getRepresentations().stream().map(this::addIncomingFileId).toList();
+		}
+
+		private IncomingFile addIncomingFileId(IncomingFile file) {
+			return file.toBuilder().id(uploadIncomingFile(file)).build();
 		}
 
 		String uploadIncomingFile(IncomingFile incomingFile) {
diff --git a/router/src/test/java/de/ozgcloud/eingang/common/zufi/GrpcOrganisationsEinheitGetResponseTestFactory.java b/router/src/test/java/de/ozgcloud/eingang/common/zufi/GrpcOrganisationsEinheitGetResponseTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..57f78b5d4db7f58699db379118409fce1d0e457c
--- /dev/null
+++ b/router/src/test/java/de/ozgcloud/eingang/common/zufi/GrpcOrganisationsEinheitGetResponseTestFactory.java
@@ -0,0 +1,15 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetResponse;
+
+public class GrpcOrganisationsEinheitGetResponseTestFactory {
+
+	public static GrpcOrganisationsEinheitGetResponse create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcOrganisationsEinheitGetResponse.Builder createBuilder() {
+		return GrpcOrganisationsEinheitGetResponse.newBuilder()
+				.setOrganisationsEinheit(GrpcOrganisationsEinheitTestFactory.create());
+	}
+}
\ No newline at end of file
diff --git a/router/src/test/java/de/ozgcloud/eingang/common/zufi/GrpcOrganisationsEinheitTestFactory.java b/router/src/test/java/de/ozgcloud/eingang/common/zufi/GrpcOrganisationsEinheitTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..49c01b101aa0caf4a3e866f329730238d3603cd4
--- /dev/null
+++ b/router/src/test/java/de/ozgcloud/eingang/common/zufi/GrpcOrganisationsEinheitTestFactory.java
@@ -0,0 +1,18 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit;
+
+public class GrpcOrganisationsEinheitTestFactory {
+
+	public static GrpcOrganisationsEinheit create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcOrganisationsEinheit.Builder createBuilder() {
+		return GrpcOrganisationsEinheit.newBuilder()
+				.setId(OrganisationsEinheitTestFactory.ID)
+				.setName(OrganisationsEinheitTestFactory.NAME)
+				.setSynonyme(OrganisationsEinheitTestFactory.SYNONYME)
+				.setVorgangManagerAddress(OrganisationsEinheitTestFactory.VORGANG_MANAGER_ADDRESS);
+	}
+}
\ No newline at end of file
diff --git a/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitMapperTest.java b/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3086fd4fa410fc82cfae8a518c84c58c172b913e
--- /dev/null
+++ b/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitMapperTest.java
@@ -0,0 +1,20 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+
+import de.ozgcloud.eingang.common.zufi.OrganisationsEinheitMapper;
+
+class OrganisationsEinheitMapperTest {
+
+	private final OrganisationsEinheitMapper mapper = Mappers.getMapper(OrganisationsEinheitMapper.class);
+
+	@Test
+	void shouldMapFromGrpc() {
+		var organisationsEinheit = mapper.fromGrpc(GrpcOrganisationsEinheitTestFactory.create());
+
+		assertThat(organisationsEinheit).usingRecursiveComparison().isEqualTo(OrganisationsEinheitTestFactory.create());
+	}
+}
\ No newline at end of file
diff --git a/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitRemoteServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitRemoteServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..320217632313129236581f6a5d61c46acf7801c9
--- /dev/null
+++ b/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitRemoteServiceTest.java
@@ -0,0 +1,70 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import de.ozgcloud.eingang.common.zufi.OrganisationsEinheit;
+import de.ozgcloud.eingang.common.zufi.OrganisationsEinheitMapper;
+import de.ozgcloud.eingang.common.zufi.OrganisationsEinheitRemoteService;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetRequest;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetResponse;
+import de.ozgcloud.zufi.grpc.organisationseinheit.OrganisationsEinheitServiceGrpc.OrganisationsEinheitServiceBlockingStub;
+
+class OrganisationsEinheitRemoteServiceTest {
+
+	@InjectMocks
+	private OrganisationsEinheitRemoteService service;
+	@Mock
+	private OrganisationsEinheitServiceBlockingStub stub;
+	@Mock
+	private OrganisationsEinheitMapper mapper;
+
+	@DisplayName("Get by id")
+	@Nested
+	class TestGetById {
+
+		private final GrpcOrganisationsEinheitGetResponse response = GrpcOrganisationsEinheitGetResponseTestFactory.create();
+		private final OrganisationsEinheit mappedOrganisationsEinheit = OrganisationsEinheitTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			when(stub.getById(any())).thenReturn(response);
+			when(mapper.fromGrpc(any())).thenReturn(mappedOrganisationsEinheit);
+		}
+
+		@Captor
+		private ArgumentCaptor<GrpcOrganisationsEinheitGetRequest> requestCaptor;
+
+		@Test
+		void shouldCallRemoteService() {
+			service.getById(OrganisationsEinheitTestFactory.ID);
+
+			verify(stub).getById(requestCaptor.capture());
+			assertThat(requestCaptor.getValue().getId()).isEqualTo(OrganisationsEinheitTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallMapper() {
+			service.getById(OrganisationsEinheitTestFactory.ID);
+
+			verify(mapper).fromGrpc(response.getOrganisationsEinheit());
+		}
+
+		@Test
+		void shouldReturnValue() {
+			var organisationsEinheit = service.getById(OrganisationsEinheitTestFactory.ID);
+
+			assertThat(organisationsEinheit).isEqualTo(mappedOrganisationsEinheit);
+		}
+	}
+}
diff --git a/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitTestFactory.java b/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2be652a78b45cc8c7d75dfa16badab8c4825606f
--- /dev/null
+++ b/router/src/test/java/de/ozgcloud/eingang/common/zufi/OrganisationsEinheitTestFactory.java
@@ -0,0 +1,27 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import java.util.UUID;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.eingang.common.zufi.OrganisationsEinheit;
+
+public class OrganisationsEinheitTestFactory {
+
+	public final static String ID = UUID.randomUUID().toString();
+	public final static String NAME = LoremIpsum.getInstance().getName();
+	public final static String SYNONYME = LoremIpsum.getInstance().getName();
+	public final static String VORGANG_MANAGER_ADDRESS = LoremIpsum.getInstance().getUrl();
+
+	public static OrganisationsEinheit create() {
+		return createBuilder().build();
+	}
+
+	public static OrganisationsEinheit.OrganisationsEinheitBuilder createBuilder() {
+		return OrganisationsEinheit.builder()
+				.id(ID)
+				.name(NAME)
+				.synonyme(SYNONYME)
+				.vorgangManagerAddress(VORGANG_MANAGER_ADDRESS);
+	}
+}
\ No newline at end of file
diff --git a/router/src/test/java/de/ozgcloud/eingang/common/zufi/ZufiServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/common/zufi/ZufiServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..04a03ee5e2a61c631f5f32c51c59df7cfd289f1b
--- /dev/null
+++ b/router/src/test/java/de/ozgcloud/eingang/common/zufi/ZufiServiceTest.java
@@ -0,0 +1,46 @@
+package de.ozgcloud.eingang.common.zufi;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+class ZufiServiceTest {
+
+	@InjectMocks
+	private ZufiService service;
+	@Mock
+	private OrganisationsEinheitRemoteService remoteService;
+
+	@DisplayName("Get vorgangManager url")
+	@Nested
+	class TestGetVorgangManagerUrl {
+
+		private final OrganisationsEinheit organisationsEinheit = OrganisationsEinheitTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			when(remoteService.getById(any())).thenReturn(organisationsEinheit);
+		}
+
+		@Test
+		void shouldCallRemoteService() {
+			service.getVorgangManagerUrl(OrganisationsEinheitTestFactory.ID);
+
+			verify(remoteService).getById(OrganisationsEinheitTestFactory.ID);
+		}
+
+		@Test
+		void shouldReturnValue() {
+			var vorgangManagerAddress = service.getVorgangManagerUrl(OrganisationsEinheitTestFactory.ID);
+
+			assertThat(vorgangManagerAddress).isEqualTo(OrganisationsEinheitTestFactory.VORGANG_MANAGER_ADDRESS);
+		}
+	}
+}
\ No newline at end of file
diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTest.java
index c470ff21d1a78c47a5a06cf963b9452d8cb0580a..b6295122f887a083f7af32445c503cfd2b80040b 100644
--- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTest.java
+++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTest.java
@@ -29,13 +29,17 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import jakarta.validation.ValidatorFactory;
+
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.eingang.Application;
 import de.ozgcloud.eingang.router.GrpcClientsProperties.ClientProperty;
-import jakarta.validation.Validation;
-import jakarta.validation.Validator;
-import jakarta.validation.ValidatorFactory;
 
 class VorgangManagerListPropertiesTest {
 
@@ -113,6 +117,37 @@ class VorgangManagerListPropertiesTest {
 		}
 	}
 
+	@Nested
+	class TestZufiRouting {
+
+		@Test
+		void shouldBeValid() {
+			var props = VorgangManagerListPropertiesTestFactory.createForZufiRouting();
+			props.setClientProperties(Optional.of(createZufiClientProperties()));
+
+			var violations = getValidator().validate(props);
+
+			assertThat(violations).isEmpty();
+		}
+
+		@Test
+		void shouldViolateMissingAddress() {
+			var props = VorgangManagerListPropertiesTestFactory.createForZufiRouting();
+
+			var violations = getValidator().validate(props);
+
+			assertThat(violations).isNotEmpty();
+		}
+
+		static GrpcClientsProperties createZufiClientProperties() {
+			var property = new ClientProperty();
+			property.setAddress(LoremIpsum.getInstance().getUrl());
+			var properties = new GrpcClientsProperties();
+			properties.setClient(Map.of(Application.ZUFI_MANAGER_GRPC_CLIENT, property));
+			return properties;
+		}
+	}
+
 	@Nested
 	class TestClientProperties {
 		private VorgangManagerListProperties props = VorgangManagerListPropertiesTestFactory.createForMultiRouting();
diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTestFactory.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTestFactory.java
index 99ed3490b7a1f664d5209441d450924b4a28a942..8425acf8fa316f549d61c7fbdf5971a92a2a48ef 100644
--- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTestFactory.java
+++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerListPropertiesTestFactory.java
@@ -68,6 +68,14 @@ class VorgangManagerListPropertiesTestFactory {
 		return props;
 	}
 
+	static VorgangManagerListProperties createForZufiRouting() {
+		var props = new VorgangManagerListProperties();
+		props.setRoutingStrategy(RoutingStrategy.ZUFI);
+		props.setFallbackStrategy(Optional.of(FallbackStrategy.DENY));
+
+		return props;
+	}
+
 	static GrpcClientsProperties createClientProperties() {
 		var property = new ClientProperty();
 		property.setAddress(ADDRESS);
diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverITCase.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverITCase.java
index 62d86f63fde8fc6d93c79b7510f097413ae55f40..cf37814049f350dfe2173ba518af58e012050b97 100644
--- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverITCase.java
+++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverITCase.java
@@ -45,9 +45,10 @@ class VorgangManagerServerResolverITCase {
 	@Test
 	void shouldReturnVorgangServiceBlockingStub() {
 		var created = resolver
-				.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID));
+				.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(
+						Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID));
 
-		assertThat(created).isNotNull().isInstanceOf(VorgangServiceBlockingStub.class);
+		assertThat(created.get()).isNotNull().isInstanceOf(VorgangServiceBlockingStub.class);
 	}
 
 	@Test
@@ -55,6 +56,6 @@ class VorgangManagerServerResolverITCase {
 		var created = resolver
 				.resolveBinaryFileServiceStubByOrganisationsEinheitId(Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID));
 
-		assertThat(created).isNotNull().isInstanceOf(BinaryFileServiceStub.class);
+		assertThat(created.get()).isNotNull().isInstanceOf(BinaryFileServiceStub.class);
 	}
 }
diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java
index b8678c338c2e676054099816056f7ff38196ba1e..7bcc1d1f45488a6b5832662ce87f7e29bc6a79df 100644
--- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java
+++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java
@@ -33,6 +33,7 @@ import java.util.Collections;
 import java.util.Optional;
 
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
@@ -40,16 +41,22 @@ import org.mockito.Mock;
 import org.mockito.Spy;
 import org.springframework.test.util.ReflectionTestUtils;
 
+import de.ozgcloud.common.errorhandling.TechnicalException;
+import de.ozgcloud.eingang.common.formdata.ZustaendigeStelleTestFactory;
+import de.ozgcloud.eingang.common.zufi.ZufiService;
 import de.ozgcloud.eingang.router.errorhandling.AdapterConfigurationException;
 import de.ozgcloud.eingang.router.errorhandling.UnknownOrganisationseinheitException;
+import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
 import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub;
 import io.grpc.Channel;
+import io.grpc.ManagedChannel;
 import io.grpc.stub.AbstractStub;
 import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
 import net.devh.boot.grpc.client.inject.StubTransformer;
 import net.devh.boot.grpc.client.stubfactory.StubFactory;
 
 class VorgangManagerServerResolverTest {
+
 	@Spy
 	@InjectMocks
 	private VorgangManagerServerResolver resolver;
@@ -59,121 +66,281 @@ class VorgangManagerServerResolverTest {
 	@Mock
 	private StubFactory stubFactory;
 
+	@Mock
+	private ZufiService zufiService;
+
 	@Nested
-	class TestCreateChannel {
+	class TestFindStubFactory {
+
+		@Mock
+		private StubFactory stubFactory;
 
 		@Test
-		void shouldCallChannelFactory() {
-			resolver.createChannelByName(VorgangManagerListPropertiesTestFactory.VORGANG_MANAGER_NAME);
+		void shouldSetApplicableFactory() {
+			when(stubFactory.isApplicable(any())).thenReturn(true);
+			setStubFactories(stubFactory, stubFactory);
 
-			verify(channelFactory).createChannel(VorgangManagerListPropertiesTestFactory.VORGANG_MANAGER_NAME);
+			resolver.findApplicableStubFactories();
+
+			assertThat(ReflectionTestUtils.getField(resolver, "vorgangBlockingStubFactory")).isSameAs(stubFactory);
+		}
+
+		@Test
+		void shouldThrowExceptionIfNotFound() {
+			setStubFactories(stubFactory);
+
+			assertThrows(AdapterConfigurationException.class, () -> resolver.findApplicableStubFactories());
+		}
+
+		private void setStubFactories(StubFactory... factories) {
+			ReflectionTestUtils.setField(resolver, "stubFactories", Arrays.asList(factories));
 		}
 	}
 
+	@DisplayName("Resolve vorgangManager service by organisationsEinheitenId")
 	@Nested
-	class TestGetFundstellenChannelName {
+	class TestResolveVorgangManagerServiceStubByOrganisationsEinheitenId {
+
+		@Mock
+		private ManagableStub<VorgangServiceBlockingStub> stub;
+
+		private final Optional<String> organisationsEinheitenId = Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID);
+
+		@BeforeEach
+		void mock() {
+			ReflectionTestUtils.setField(resolver, "vorgangBlockingStubFactory", stubFactory);
+
+			doReturn(stub).when(resolver).createStub(any(), any(), any());
+		}
+
+		@Test
+		void shouldCallCreateStub() {
+			resolveStub();
+
+			verify(resolver).createStub(organisationsEinheitenId, stubFactory, VorgangServiceBlockingStub.class);
+		}
+
+		@Test
+		void shouldReturnStub() {
+			var createdStub = resolveStub();
+
+			assertThat(createdStub).isEqualTo(stub);
+		}
+
+		private ManagableStub<VorgangServiceBlockingStub> resolveStub() {
+			return resolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitenId);
+		}
+	}
+
+	@DisplayName("Resolve binaryFile service by organisationsEinheitenId")
+	@Nested
+	class TestResolveBinaryFileServiceStubByOrganisationsEinheitenId {
+
+		@Mock
+		private ManagableStub<BinaryFileServiceStub> stub;
+
+		private final Optional<String> organisationsEinheitenId = Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID);
+
+		@BeforeEach
+		void mock() {
+			ReflectionTestUtils.setField(resolver, "binaryFileStubFactory", stubFactory);
+
+			doReturn(stub).when(resolver).createStub(any(), any(), any());
+		}
+
+		@Test
+		void shouldCallCreateStub() {
+			resolveStub();
+
+			verify(resolver).createStub(organisationsEinheitenId, stubFactory, BinaryFileServiceStub.class);
+		}
 
+		@Test
+		void shouldReturnStub() {
+			var createdStub = resolveStub();
+
+			assertThat(createdStub).isEqualTo(stub);
+		}
+
+		private ManagableStub<BinaryFileServiceStub> resolveStub() {
+			return resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(organisationsEinheitenId);
+		}
+	}
+
+	@DisplayName("Create stub")
+	@Nested
+	class TestCreateStub {
+
+		@Mock
+		private ManagableStub<?> stub;
+
+		private final Optional<String> organisationsEinheitenId = Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID);
+
+		@DisplayName("on zufi strategy")
 		@Nested
-		class TestStrategyFundstelle {
+		class TestOnZufiRoutingStrategy {
 
-			@Test
-			void shouldCreateChannel() {
-				setProperties(VorgangManagerListPropertiesTestFactory.createWithFundstelle());
+			@BeforeEach
+			void mock() {
+				doReturn(stub).when(resolver).createCloseableStub(any(), any(), any());
+				setProperties(VorgangManagerListPropertiesTestFactory.createForZufiRouting());
+			}
 
-				var channel = resolver.getFundstelleChannelName();
+			@Test
+			void shouldCallCreateStub() {
+				createStub();
 
-				assertThat(channel).isNotNull().isEqualTo(VorgangManagerListPropertiesTestFactory.FUNDSTELLE_CHANNEL_NAME);
+				verify(resolver).createStub(organisationsEinheitenId, stubFactory, VorgangServiceBlockingStub.class);
 			}
 
 			@Test
-			void shouldThrowExceptionIfFundstelleIsMissing() {
-				var props = VorgangManagerListPropertiesTestFactory.createWithFundstelle();
-				props.setFundstelleVorgangManagerName(Optional.empty());
-				setProperties(props);
+			void shouldReturnStub() {
+				var createdStub = createStub();
 
-				assertThrows(AdapterConfigurationException.class, () -> resolver.getFundstelleChannelName());
+				assertThat(createdStub).isEqualTo(stub);
 			}
 		}
 
+		@DisplayName("On other routing strategy")
 		@Nested
-		class TestStrategyDeny {
+		class TestOnOtherRoutingStrategy {
+
+			@BeforeEach
+			void mock() {
+				doReturn(stub).when(resolver).createStubByConfiguredChannels(any(), any(), any());
+				setProperties(VorgangManagerListPropertiesTestFactory.createForSingleRouting());
+			}
 
 			@Test
-			void shouldThrowException() {
-				setProperties(VorgangManagerListPropertiesTestFactory.createForMultiRouting());
+			void shouldCallCreateStub() {
+				createStub();
 
-				assertThrows(UnknownOrganisationseinheitException.class, () -> resolver.getFundstelleChannelName());
+				verify(resolver).createStubByConfiguredChannels(organisationsEinheitenId, stubFactory, VorgangServiceBlockingStub.class);
+			}
+
+			@Test
+			void shouldReturnStub() {
+				var createdStub = createStub();
+
+				assertThat(createdStub).isEqualTo(stub);
 			}
 		}
+
+		private ManagableStub<VorgangServiceBlockingStub> createStub() {
+			return resolver.createStub(organisationsEinheitenId, stubFactory, VorgangServiceBlockingStub.class);
+		}
 	}
 
+	@DisplayName("Create closeable stub")
 	@Nested
-	class TestGetChannelName {
+	class TestCreateCloseableStub {
+
+		@Mock
+		private ManagableStub<?> manageableStub;
+		@Mock
+		private AbstractStub<?> stub;
+		@Mock
+		private ManagedChannel managedChannel;
+
+		private Optional<String> organisationsEinheitenId = Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID);
+		private final String vorgangManagerAddress = "dummyVorgangManagerAddress";
+
+		@BeforeEach
+		void mock() {
+			doReturn(vorgangManagerAddress).when(resolver).getVorgangManagerAddress(any());
+			doReturn(managedChannel).when(resolver).createChannel(any());
+			doReturn(stub).when(resolver).applyStubTransformers(any(), any());
+		}
 
 		@Test
-		void shouldUseSingleName() {
-			setProperties(VorgangManagerListPropertiesTestFactory.createForSingleRouting());
+		void shouldGetVorgangManagerAddress() {
+			createCloseableStub();
 
-			var name = resolver.getChannelName(Optional.empty());
+			verify(resolver).getVorgangManagerAddress(organisationsEinheitenId);
+		}
 
-			assertThat(name).contains(VorgangManagerListPropertiesTestFactory.CHANNEL_NAME);
+		@Test
+		void shouldCreateChannel() {
+			createCloseableStub();
+
+			verify(resolver).createChannel(vorgangManagerAddress);
 		}
 
 		@Test
-		void shouldUseNameFromMap() {
-			setProperties(VorgangManagerListPropertiesTestFactory.createForMultiRouting());
+		void shouldCreateStub() {
+			createCloseableStub();
 
-			var name = resolver.getChannelName(Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID));
+			verify(stubFactory).createStub(VorgangServiceBlockingStub.class, managedChannel);
+		}
 
-			assertThat(name).contains(VorgangManagerListPropertiesTestFactory.CHANNEL_NAME);
+		@Test
+		void shouldApplStubTransformers() {
+			createCloseableStub();
+
+			verify(resolver).applyStubTransformers(any(), eq(vorgangManagerAddress));
 		}
 
 		@Test
-		void shouldGetFundstellenName() {
-			setProperties(VorgangManagerListPropertiesTestFactory.createWithFundstelle());
+		void shouldReturnStub() {
+			var createdStub = (ClosableStub) createCloseableStub();
 
-			var name = resolver.getChannelName(Optional.of("4711"));
+			assertThat(createdStub).isNotNull();
+			assertThat(createdStub.get()).isEqualTo(stub);
+		}
 
-			verify(resolver).getFundstelleChannelName();
-			assertThat(name).isEqualTo(VorgangManagerListPropertiesTestFactory.FUNDSTELLE_CHANNEL_NAME);
+		private ManagableStub<VorgangServiceBlockingStub> createCloseableStub() {
+			return resolver.createCloseableStub(organisationsEinheitenId, stubFactory, VorgangServiceBlockingStub.class);
 		}
 	}
 
+	@DisplayName("Get vorgangManager address")
 	@Nested
-	class TestFindStubFactory {
+	class TestGetVorgangManagerAddress {
 
-		@Mock
-		private StubFactory stubFactory;
+		private final Optional<String> organisationsEinheitenId = Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID);
+		private final String vorgangManagerAddress = "DummyVorgangManagerAddress";
 
 		@Test
-		void shouldSetApplicableFactory() {
-			when(stubFactory.isApplicable(any())).thenReturn(true);
-			setStubFactories(stubFactory, stubFactory);
+		void shouldCallZufiService() {
+			when(zufiService.getVorgangManagerUrl(any())).thenReturn(vorgangManagerAddress);
 
-			resolver.findApplicableStubFactories();
+			getVorgangManagerAddress();
 
-			assertThat(ReflectionTestUtils.getField(resolver, "vorgangStubFactory")).isSameAs(stubFactory);
+			verify(zufiService).getVorgangManagerUrl(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID);
 		}
 
 		@Test
-		void shouldThrowExceptionIfNotFound() {
-			setStubFactories(stubFactory);
+		void shouldThrowExceptionIfOrganisationsEinheitIsNotPresent() {
+			var emptyOrganisationsEinheitId = Optional.<String>empty();
 
-			assertThrows(AdapterConfigurationException.class, () -> resolver.findApplicableStubFactories());
+			assertThatThrownBy(() -> resolver.getVorgangManagerAddress(emptyOrganisationsEinheitId)).isInstanceOf(TechnicalException.class);
 		}
 
-		private void setStubFactories(StubFactory... factories) {
-			ReflectionTestUtils.setField(resolver, "stubFactories", Arrays.asList(factories));
+		@Test
+		void shouldReturnAddress() {
+			when(zufiService.getVorgangManagerUrl(any())).thenReturn(vorgangManagerAddress);
+
+			var address = getVorgangManagerAddress();
+
+			assertThat(address).isEqualTo(vorgangManagerAddress);
+
+		}
+
+		private String getVorgangManagerAddress() {
+			return resolver.getVorgangManagerAddress(organisationsEinheitenId);
 		}
 	}
 
+	@DisplayName("Create stub by configured channels")
 	@Nested
-	class TestCreateStub {
+	class TestCreateStubByConfiguredChannels {
 
 		@Mock
 		private Channel channel;
 		@Mock
 		private StubFactory stubFactory;
+		@Mock
+		private AbstractStub<?> createdStub;
 
 		private Class<? extends AbstractStub<?>> stubClass = VorgangServiceBlockingStub.class;
 
@@ -181,31 +348,121 @@ class VorgangManagerServerResolverTest {
 		void initTest() {
 			doReturn(VorgangManagerListPropertiesTestFactory.CHANNEL_NAME).when(resolver).getChannelName(any());
 			doReturn(channel).when(resolver).createChannelByName(any());
+			setProperties(VorgangManagerListPropertiesTestFactory.createForSingleRouting());
+			doReturn(createdStub).when(resolver).applyStubTransformers(any(), any());
 		}
 
 		@Test
 		void shouldGetChannel() {
-			createStub();
+			createStubByConfiguredChannels();
 
 			verify(resolver).createChannelByName(VorgangManagerListPropertiesTestFactory.CHANNEL_NAME);
 		}
 
 		@Test
 		void shouldApplyTransformers() {
-			createStub();
+			createStubByConfiguredChannels();
 
 			verify(resolver).applyStubTransformers(any(), any());
 		}
 
 		@Test
 		void shouldCreateStubByFactory() {
-			createStub();
+			createStubByConfiguredChannels();
 
 			verify(stubFactory).createStub(eq(stubClass), any());
 		}
 
-		private AbstractStub<?> createStub() {
-			return resolver.createStub(Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID), stubFactory, stubClass);
+		@Test
+		void shouldReturnStub() {
+			var stub = createStubByConfiguredChannels();
+
+			assertThat(stub.get()).isEqualTo(createdStub);
+		}
+
+		private ManagableStub<?> createStubByConfiguredChannels() {
+			return resolver.createStubByConfiguredChannels(Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID), stubFactory,
+					VorgangServiceBlockingStub.class);
+		}
+	}
+
+	@Nested
+	class TestGetChannelName {
+
+		@Test
+		void shouldUseSingleName() {
+			setProperties(VorgangManagerListPropertiesTestFactory.createForSingleRouting());
+
+			var name = resolver.getChannelName(Optional.empty());
+
+			assertThat(name).contains(VorgangManagerListPropertiesTestFactory.CHANNEL_NAME);
+		}
+
+		@Test
+		void shouldUseNameFromMap() {
+			setProperties(VorgangManagerListPropertiesTestFactory.createForMultiRouting());
+
+			var name = resolver.getChannelName(Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID));
+
+			assertThat(name).contains(VorgangManagerListPropertiesTestFactory.CHANNEL_NAME);
+		}
+
+		@Test
+		void shouldGetFundstellenName() {
+			setProperties(VorgangManagerListPropertiesTestFactory.createWithFundstelle());
+
+			var name = resolver.getChannelName(Optional.of("4711"));
+
+			verify(resolver).getFundstelleChannelName();
+			assertThat(name).isEqualTo(VorgangManagerListPropertiesTestFactory.FUNDSTELLE_CHANNEL_NAME);
+		}
+	}
+
+	@Nested
+	class TestGetFundstellenChannelName {
+
+		@Nested
+		class TestStrategyFundstelle {
+
+			@Test
+			void shouldCreateChannel() {
+				setProperties(VorgangManagerListPropertiesTestFactory.createWithFundstelle());
+
+				var channel = resolver.getFundstelleChannelName();
+
+				assertThat(channel).isNotNull().isEqualTo(VorgangManagerListPropertiesTestFactory.FUNDSTELLE_CHANNEL_NAME);
+			}
+
+			@Test
+			void shouldThrowExceptionIfFundstelleIsMissing() {
+				var props = VorgangManagerListPropertiesTestFactory.createWithFundstelle();
+				props.setFundstelleVorgangManagerName(Optional.empty());
+				setProperties(props);
+
+				assertThrows(AdapterConfigurationException.class, () -> resolver.getFundstelleChannelName());
+			}
+		}
+
+		@Nested
+		class TestStrategyDeny {
+
+			@Test
+			void shouldThrowException() {
+				setProperties(VorgangManagerListPropertiesTestFactory.createForMultiRouting());
+
+				assertThrows(UnknownOrganisationseinheitException.class, () -> resolver.getFundstelleChannelName());
+			}
+		}
+	}
+
+	@Nested
+	class TestCreateChannelByName {
+
+		@Test
+		void shouldCallChannelFactory() {
+			resolver.createChannelByName(VorgangManagerListPropertiesTestFactory.VORGANG_MANAGER_NAME);
+
+			verify(channelFactory).createChannel(VorgangManagerListPropertiesTestFactory.VORGANG_MANAGER_NAME);
 		}
 	}
 
@@ -233,4 +490,4 @@ class VorgangManagerServerResolverTest {
 	private void setProperties(VorgangManagerListProperties properties) {
 		ReflectionTestUtils.setField(resolver, "properties", properties);
 	}
-}
+}
\ No newline at end of file
diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java
index 60206de34962325a9a4b66061f7f65617233cec3..465b61fcdbe88fc611f3990c2a6ec00d5073ab96 100644
--- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java
+++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.*;
 
 import java.io.InputStream;
 import java.util.List;
+import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -37,6 +38,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -45,6 +47,7 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Spy;
 
 import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender;
 import de.ozgcloud.common.errorhandling.TechnicalException;
@@ -54,6 +57,7 @@ import de.ozgcloud.eingang.common.formdata.IncomingFile;
 import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
 import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory;
 import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory;
+import de.ozgcloud.eingang.common.formdata.ZustaendigeStelleTestFactory;
 import de.ozgcloud.eingang.router.VorgangRemoteService.VorgangCreator;
 import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
 import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileMetaData;
@@ -70,14 +74,11 @@ import lombok.SneakyThrows;
 
 class VorgangRemoteServiceTest {
 
+	@Spy
 	@InjectMocks
 	private VorgangRemoteService remoteService;
 	@Mock
-	private final VorgangServiceBlockingStub vorgangStub = VorgangManagerServerResolverTestFactory.createVorgangBlockingStub();
-	@Mock
-	private final BinaryFileServiceStub binaryFileStub = VorgangManagerServerResolverTestFactory.createBinaryFileStub();
-	@Mock
-	private GrpcEingangMapper eingangMapper;
+	private VorgangManagerServerResolver resolver;
 
 	private VorgangCreator vorgangCreator;
 
@@ -87,286 +88,434 @@ class VorgangRemoteServiceTest {
 			.addRepresentations(GrpcIncomingFileTestFactory.create())
 			.build();
 	private final String vorgangId = UUID.randomUUID().toString();
-	private String fileId = "42";
-
-	@BeforeEach
-	void init() {
-		vorgangCreator = spy(remoteService.new VorgangCreator(formData, eingang, vorgangStub, binaryFileStub));
-	}
+	private final String fileId = "42";
 
+	@DisplayName("Create vorgang")
 	@Nested
 	class TestCreateVorgang {
 
 		@Mock
-		private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver;
-		@Captor
-		private ArgumentCaptor<GrpcCreateVorgangRequest> requestCaptor;
-		@Captor
-		private ArgumentCaptor<GrpcFinishCreationRequest> finishRequestCaptor;
+		private ManagableStub<VorgangServiceBlockingStub> managableVorgangServiceStub;
+		@Mock
+		private VorgangServiceBlockingStub vorgangServiceStub;
+
+		@Mock
+		private ManagableStub<BinaryFileServiceStub> managableBinaryFileServiceStub;
+		@Mock
+		private BinaryFileServiceStub binaryFileServiceStub;
 
-		private final GrpcCreateVorgangResponse createVorgangResponse = GrpcCreateVorgangResponse.newBuilder().setVorgangId(vorgangId).build();
-		private final GrpcFinishCreationResponse finishResponse = GrpcFinishCreationResponse.newBuilder().setMessage("OK").build();
+		private final Optional<String> organisationsEinheitId = Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID);
 
+		@SneakyThrows
 		@BeforeEach
-		void init() {
-			when(vorgangStub.startCreation(any())).thenReturn(createVorgangResponse);
-			when(vorgangStub.finishCreation(any())).thenReturn(finishResponse);
-			doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any());
-			doReturn(GrpcFinishCreationRequest.newBuilder().build()).when(vorgangCreator).buildFinishCreationRequest();
-		}
+		void mock() {
+			when(resolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(any())).thenReturn(managableVorgangServiceStub);
+			when(managableVorgangServiceStub.get()).thenReturn(vorgangServiceStub);
 
-		@Test
-		void shouldStartCreation() {
-			createVorgang();
+			when(resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(any())).thenReturn(managableBinaryFileServiceStub);
+			when(managableBinaryFileServiceStub.get()).thenReturn(binaryFileServiceStub);
 
-			verify(vorgangStub).startCreation(any(GrpcCreateVorgangRequest.class));
+			doNothing().when(remoteService).logConnection(any(), any());
+			doNothing().when(remoteService).finishStubConnections(any());
 		}
 
-		@Test
-		void shouldStartCreationWithEmptyAttachmetns() {
-			createVorgang();
+		@DisplayName("with no exception occuring")
+		@Nested
+		class TestWithNoException {
 
-			verify(vorgangStub).startCreation(requestCaptor.capture());
-			assertThat(requestCaptor.getValue().getEingang().getAttachmentsList()).isEmpty();
-		}
+			@SneakyThrows
+			@BeforeEach
+			void mock() {
+				doReturn(vorgangId).when(remoteService).createVorgang(any(), any(), any(), any());
+			}
 
-		@Test
-		void shouldStartCreationWithEmptyRepresentations() {
-			createVorgang();
+			@Test
+			void shouldGetVorgangService() {
+				createVorgang();
 
-			verify(vorgangStub).startCreation(requestCaptor.capture());
-			assertThat(requestCaptor.getValue().getEingang().getRepresentationsList()).isEmpty();
-		}
+				verify(resolver).resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitId);
+			}
 
-		@Test
-		void shouldCallUploadAttachments() {
-			createVorgang();
+			@Test
+			void shouldGetBinaryFileService() {
+				createVorgang();
 
-			verify(vorgangCreator).uploadAttachments();
-		}
+				verify(resolver).resolveBinaryFileServiceStubByOrganisationsEinheitId(organisationsEinheitId);
+			}
 
-		@Test
-		void shouldCallUploadRepresentations() {
-			createVorgang();
+			@SneakyThrows
+			@Test
+			void shouldCreateVorgang() {
+				createVorgang();
 
-			verify(vorgangCreator).uploadRepresentations();
-		}
+				verify(remoteService).createVorgang(formData, eingang, vorgangServiceStub, binaryFileServiceStub);
+			}
 
-		@Test
-		void shouldFinishCreation() {
-			createVorgang();
+			@Test
+			void shouldFinishStubConnection() {
+				createVorgang();
+
+				verify(remoteService).finishStubConnections(List.of(managableVorgangServiceStub, managableBinaryFileServiceStub));
+			}
 
-			verify(vorgangStub).finishCreation(finishRequestCaptor.capture());
-			assertThat(finishRequestCaptor.getValue()).isInstanceOf(GrpcFinishCreationRequest.class);
+			@Test
+			void shouldReturnVorgangId() {
+				var created = createVorgang();
+
+				assertThat(created).isEqualTo(vorgangId);
+
+			}
 		}
 
-		@Test
-		void shouldReturnVorgangId() {
-			var result = createVorgang();
+		@DisplayName("on exception")
+		@Nested
+		class TestOnException {
 
-			assertThat(result).isEqualTo(vorgangId);
+			@SneakyThrows
+			@BeforeEach
+			void mock() {
+				doThrow(RuntimeException.class).when(remoteService).createVorgang(any(), any(), any(), any());
+			}
+
+			@SneakyThrows
+			@Test
+			void shouldFinishStubConnections() {
+				try {
+					createVorgang();
+				} catch (Exception e) {
+					// Do nothing
+				}
+
+				verify(remoteService).finishStubConnections(List.of(managableVorgangServiceStub, managableBinaryFileServiceStub));
+			}
 		}
 
+		@SneakyThrows
 		private String createVorgang() {
-			return vorgangCreator.create();
+			return remoteService.createVorgang(formData, eingang, organisationsEinheitId);
 		}
 	}
 
+	@DisplayName("Finish stub connections")
 	@Nested
-	class TestUploadAttachments {
+	class TestFinishStubConnections {
+
+		@Mock
+		private ClosableStub<VorgangServiceBlockingStub> closableStub;
 
 		@BeforeEach
-		void mockFileId() {
-			doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any());
+		void mock() {
+			when(closableStub.isShutdownable()).thenReturn(true);
+			doNothing().when(closableStub).close();
 		}
 
 		@Test
-		void shouldCallUploadIncomingFile() {
-			vorgangCreator.uploadAttachments();
+		void shouldCheckIfSubIsShutdownable() {
+			remoteService.finishStubConnections(List.of(closableStub));
 
-			verify(vorgangCreator, times(2)).uploadIncomingFile(any(IncomingFile.class));
+			verify(closableStub).isShutdownable();
 		}
 
 		@Test
-		void shouldSetFileId() {
-			var uploadedAttachments = vorgangCreator.uploadAttachments();
+		void shouldShutDownChannelForClosableStubs() {
+			remoteService.finishStubConnections(List.of(closableStub));
 
-			assertThat(uploadedAttachments.get(0).getFiles().get(0).getId()).isEqualTo(fileId);
+			verify((ClosableStub) closableStub).close();
 		}
 	}
 
+	@DisplayName("VorgangCreator")
 	@Nested
-	class TestUploadRepresentations {
+	class TestVorgangCreator {
+
+		@Mock
+		private final VorgangServiceBlockingStub vorgangStub = VorgangManagerServerResolverTestFactory.createVorgangBlockingStub();
+		@Mock
+		private final BinaryFileServiceStub binaryFileStub = VorgangManagerServerResolverTestFactory.createBinaryFileStub();
+		@Mock
+		private GrpcEingangMapper eingangMapper;
 
 		@BeforeEach
-		void mockFileId() {
-			doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any());
+		void init() {
+			vorgangCreator = spy(remoteService.new VorgangCreator(formData, eingang, vorgangStub, binaryFileStub));
 		}
 
-		@Test
-		void shouldCallUploadIncomingFile() {
-			vorgangCreator.uploadRepresentations();
+		@Nested
+		class TestCreateVorgang {
 
-			verify(vorgangCreator).uploadIncomingFile(any(IncomingFile.class));
-		}
+			@Mock
+			private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver;
+			@Captor
+			private ArgumentCaptor<GrpcCreateVorgangRequest> requestCaptor;
+			@Captor
+			private ArgumentCaptor<GrpcFinishCreationRequest> finishRequestCaptor;
 
-		@Test
-		void shouldSetFileId() {
-			var uploadedRepresentations = vorgangCreator.uploadRepresentations();
+			private final GrpcCreateVorgangResponse createVorgangResponse = GrpcCreateVorgangResponse.newBuilder().setVorgangId(vorgangId).build();
+			private final GrpcFinishCreationResponse finishResponse = GrpcFinishCreationResponse.newBuilder().setMessage("OK").build();
 
-			assertThat(uploadedRepresentations.get(0).getId()).isEqualTo(fileId);
-		}
-	}
+			@BeforeEach
+			void init() {
+				when(vorgangStub.startCreation(any())).thenReturn(createVorgangResponse);
+				when(vorgangStub.finishCreation(any())).thenReturn(finishResponse);
+				doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any());
+				doReturn(GrpcFinishCreationRequest.newBuilder().build()).when(vorgangCreator).buildFinishCreationRequest();
+			}
 
-	@Nested
-	class TestBuildMetaDataRequest {
+			@Test
+			void shouldStartCreation() {
+				createVorgang();
 
-		@BeforeEach
-		void mockMapper() {
-			doReturn(vorgangId).when(vorgangCreator).getVorgangId();
-		}
+				verify(vorgangStub).startCreation(any(GrpcCreateVorgangRequest.class));
+			}
 
-		@Test
-		void shouldContainsContext() {
-			var metaData = buildMetaData();
+			@Test
+			void shouldStartCreationWithEmptyAttachmetns() {
+				createVorgang();
 
-			assertThat(metaData.getContext().getClient()).isEqualTo(VorgangRemoteService.VorgangCreator.CALL_CONTEXT_CLIENT);
-		}
+				verify(vorgangStub).startCreation(requestCaptor.capture());
+				assertThat(requestCaptor.getValue().getEingang().getAttachmentsList()).isEmpty();
+			}
 
-		@Test
-		void shouldContainsVorgangId() {
-			var metaData = buildMetaData();
+			@Test
+			void shouldStartCreationWithEmptyRepresentations() {
+				createVorgang();
 
-			assertThat(metaData.getVorgangId()).isEqualTo(vorgangId);
-		}
+				verify(vorgangStub).startCreation(requestCaptor.capture());
+				assertThat(requestCaptor.getValue().getEingang().getRepresentationsList()).isEmpty();
+			}
 
-		@Test
-		void shouldContainsField() {
-			var metaData = buildMetaData();
+			@Test
+			void shouldCallUploadAttachments() {
+				createVorgang();
 
-			assertThat(metaData.getField()).isEqualTo(VorgangRemoteService.VorgangCreator.VORGANG_ATTACHMENT_FIELD);
-		}
+				verify(vorgangCreator).uploadAttachments();
+			}
 
-		@Test
-		void shouldContainsContentType() {
-			var metaData = buildMetaData();
+			@Test
+			void shouldCallUploadRepresentations() {
+				createVorgang();
 
-			assertThat(metaData.getContentType()).isEqualTo(IncomingFileTestFactory.CONTENT_TYPE);
-		}
+				verify(vorgangCreator).uploadRepresentations();
+			}
 
-		@Test
-		void shouldContainsSize() {
-			var metaData = buildMetaData();
+			@Test
+			void shouldFinishCreation() {
+				createVorgang();
 
-			assertThat(metaData.getSize()).isEqualTo(IncomingFileTestFactory.SIZE);
-		}
+				verify(vorgangStub).finishCreation(finishRequestCaptor.capture());
+				assertThat(finishRequestCaptor.getValue()).isInstanceOf(GrpcFinishCreationRequest.class);
+			}
 
-		@Test
-		void shouldContainsFileName() {
-			var metaData = buildMetaData();
+			@Test
+			void shouldReturnVorgangId() {
+				var result = createVorgang();
 
-			assertThat(metaData.getFileName()).isEqualTo(IncomingFileTestFactory.NAME);
-		}
+				assertThat(result).isEqualTo(vorgangId);
+			}
 
-		private GrpcUploadBinaryFileMetaData buildMetaData() {
-			return vorgangCreator.buildMetaDataRequest(IncomingFileTestFactory.create()).getMetadata();
+			@SneakyThrows
+			private String createVorgang() {
+				return vorgangCreator.create();
+			}
 		}
-	}
 
-	@Nested
-	class TestWaitUntilFutureToComplete {
+		@Nested
+		class TestUploadAttachments {
 
-		@Mock
-		private FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> sender;
+			@BeforeEach
+			void mockFileId() {
+				doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any());
+			}
 
-		@Mock
-		private CompletableFuture<GrpcUploadBinaryFileResponse> streamFuture;
+			@Test
+			void shouldCallUploadIncomingFile() {
+				vorgangCreator.uploadAttachments();
 
-		@Mock
-		private InputStream inputStream;
+				verify(vorgangCreator, times(2)).uploadIncomingFile(any(IncomingFile.class));
+			}
 
-		@BeforeEach
-		void initSender() {
-			when(sender.getResultFuture()).thenReturn(streamFuture);
-		}
+			@Test
+			void shouldSetFileId() {
+				var uploadedAttachments = vorgangCreator.uploadAttachments();
 
-		@Test
-		void shouldNotThrowException() {
-			assertDoesNotThrow(() -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream));
+				assertThat(uploadedAttachments.get(0).getFiles().get(0).getId()).isEqualTo(fileId);
+			}
 		}
 
-		@ParameterizedTest
-		@ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class })
-		void shouldRethrowAsTechnicalException(Class<Exception> exception)
-				throws InterruptedException, ExecutionException, TimeoutException {
-			doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class));
+		@Nested
+		class TestUploadRepresentations {
 
-			assertThrows(TechnicalException.class, () -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream));
-		}
+			@BeforeEach
+			void mockFileId() {
+				doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any());
+			}
 
-		@ParameterizedTest
-		@ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class })
-		@SneakyThrows
-		void shouldCloseFileContentStreamOnException(Class<Exception> exception) {
-			doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class));
+			@Test
+			void shouldCallUploadIncomingFile() {
+				vorgangCreator.uploadRepresentations();
 
-			try {
-				vorgangCreator.waitUntilFutureToComplete(sender, inputStream);
-			} catch (Exception e) {
-				// ignored
+				verify(vorgangCreator).uploadIncomingFile(any(IncomingFile.class));
+			}
+
+			@Test
+			void shouldSetFileId() {
+				var uploadedRepresentations = vorgangCreator.uploadRepresentations();
+
+				assertThat(uploadedRepresentations.get(0).getId()).isEqualTo(fileId);
 			}
-			verify(inputStream).close();
 		}
 
-		@Test
-		@SneakyThrows
-		void shouldCloseFileContent() {
-			try {
-				vorgangCreator.waitUntilFutureToComplete(sender, inputStream);
-			} catch (Exception e) {
-				// ignored
+		@Nested
+		class TestBuildMetaDataRequest {
+
+			@BeforeEach
+			void mockMapper() {
+				doReturn(vorgangId).when(vorgangCreator).getVorgangId();
 			}
 
-			verify(inputStream).close();
-		}
-	}
+			@Test
+			void shouldContainsContext() {
+				var metaData = buildMetaData();
 
-	@Nested
-	class TestBuildFinishCreationRequest {
+				assertThat(metaData.getContext().getClient()).isEqualTo(VorgangRemoteService.VorgangCreator.CALL_CONTEXT_CLIENT);
+			}
 
-		private final IncomingFileGroup attachment = IncomingFileGroupTestFactory.create();
-		private final IncomingFile representation = IncomingFileTestFactory.create();
+			@Test
+			void shouldContainsVorgangId() {
+				var metaData = buildMetaData();
 
-		@BeforeEach
-		void mock() {
-			doReturn(vorgangId).when(vorgangCreator).getVorgangId();
-			doReturn(List.of(attachment)).when(vorgangCreator).getUploadedAttachments();
-			doReturn(List.of(representation)).when(vorgangCreator).getUploadedRepresentations();
-		}
+				assertThat(metaData.getVorgangId()).isEqualTo(vorgangId);
+			}
 
-		@Test
-		void shouldContainsVorgangId() {
-			var request = buildFinishCreationRequest();
+			@Test
+			void shouldContainsField() {
+				var metaData = buildMetaData();
 
-			assertThat(request.getVorgangId()).isEqualTo(vorgangId);
-		}
+				assertThat(metaData.getField()).isEqualTo(VorgangRemoteService.VorgangCreator.VORGANG_ATTACHMENT_FIELD);
+			}
 
-		@Test
-		void shouldContainsAttachmentWithoutContent() {
-			var request = buildFinishCreationRequest();
+			@Test
+			void shouldContainsContentType() {
+				var metaData = buildMetaData();
+
+				assertThat(metaData.getContentType()).isEqualTo(IncomingFileTestFactory.CONTENT_TYPE);
+			}
+
+			@Test
+			void shouldContainsSize() {
+				var metaData = buildMetaData();
+
+				assertThat(metaData.getSize()).isEqualTo(IncomingFileTestFactory.SIZE);
+			}
 
-			assertThat(request.getAttachments(0).getFiles(0).getContent()).isEmpty();
+			@Test
+			void shouldContainsFileName() {
+				var metaData = buildMetaData();
+
+				assertThat(metaData.getFileName()).isEqualTo(IncomingFileTestFactory.NAME);
+			}
+
+			private GrpcUploadBinaryFileMetaData buildMetaData() {
+				return vorgangCreator.buildMetaDataRequest(IncomingFileTestFactory.create()).getMetadata();
+			}
 		}
 
-		@Test
-		void shouldContainsRepresentationsWithoutContent() {
-			var request = buildFinishCreationRequest();
+		@Nested
+		class TestWaitUntilFutureToComplete {
+
+			@Mock
+			private FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> sender;
+
+			@Mock
+			private CompletableFuture<GrpcUploadBinaryFileResponse> streamFuture;
+
+			@Mock
+			private InputStream inputStream;
+
+			@BeforeEach
+			void initSender() {
+				when(sender.getResultFuture()).thenReturn(streamFuture);
+			}
+
+			@Test
+			void shouldNotThrowException() {
+				assertDoesNotThrow(() -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream));
+			}
+
+			@ParameterizedTest
+			@ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class })
+			void shouldRethrowAsTechnicalException(Class<Exception> exception)
+					throws InterruptedException, ExecutionException, TimeoutException {
+				doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class));
+
+				assertThrows(TechnicalException.class, () -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream));
+			}
+
+			@ParameterizedTest
+			@ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class })
+			@SneakyThrows
+			void shouldCloseFileContentStreamOnException(Class<Exception> exception) {
+				doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class));
+
+				waitUntilFutureToComplete();
+
+				verify(inputStream).close();
+			}
 
-			assertThat(request.getRepresentations(0).getContent()).isEmpty();
+			@Test
+			@SneakyThrows
+			void shouldCloseFileContent() {
+				waitUntilFutureToComplete();
+
+				verify(inputStream).close();
+			}
+
+			private void waitUntilFutureToComplete() {
+				try {
+					vorgangCreator.waitUntilFutureToComplete(sender, inputStream);
+				} catch (Exception e) {
+					// ignored
+				}
+			}
 		}
 
-		private GrpcFinishCreationRequest buildFinishCreationRequest() {
-			return vorgangCreator.buildFinishCreationRequest();
+		@Nested
+		class TestBuildFinishCreationRequest {
+
+			private final IncomingFileGroup attachment = IncomingFileGroupTestFactory.create();
+			private final IncomingFile representation = IncomingFileTestFactory.create();
+
+			@BeforeEach
+			void mock() {
+				doReturn(vorgangId).when(vorgangCreator).getVorgangId();
+				doReturn(List.of(attachment)).when(vorgangCreator).getUploadedAttachments();
+				doReturn(List.of(representation)).when(vorgangCreator).getUploadedRepresentations();
+			}
+
+			@Test
+			void shouldContainsVorgangId() {
+				var request = buildFinishCreationRequest();
+
+				assertThat(request.getVorgangId()).isEqualTo(vorgangId);
+			}
+
+			@Test
+			void shouldContainsAttachmentWithoutContent() {
+				var request = buildFinishCreationRequest();
+
+				assertThat(request.getAttachments(0).getFiles(0).getContent()).isEmpty();
+			}
+
+			@Test
+			void shouldContainsRepresentationsWithoutContent() {
+				var request = buildFinishCreationRequest();
+
+				assertThat(request.getRepresentations(0).getContent()).isEmpty();
+			}
+
+			private GrpcFinishCreationRequest buildFinishCreationRequest() {
+				return vorgangCreator.buildFinishCreationRequest();
+			}
 		}
 	}
 }
\ No newline at end of file