diff --git a/common/src/main/java/de/itvsh/kop/eingangsadapter/common/formdata/FormData.java b/common/src/main/java/de/itvsh/kop/eingangsadapter/common/formdata/FormData.java
index 13c2ae6a991021ba2213b87fa3cf35720db2f248..69d9b6a844ed317d894f6ced26aa565c4a3e7a71 100644
--- a/common/src/main/java/de/itvsh/kop/eingangsadapter/common/formdata/FormData.java
+++ b/common/src/main/java/de/itvsh/kop/eingangsadapter/common/formdata/FormData.java
@@ -18,7 +18,7 @@ public class FormData {
 
 	@NotNull
 	@Builder.Default
-	private UUID id = UUID.randomUUID();
+	private String id = UUID.randomUUID().toString();
 
 	private FormHeader header;
 
diff --git a/forwarder/pom.xml b/forwarder/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e9e89f216f37fef911eb90ad7b833fafa9bb3a9f
--- /dev/null
+++ b/forwarder/pom.xml
@@ -0,0 +1,90 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>de.itvsh.kop.eingangsadapter</groupId>
+		<artifactId>parent</artifactId>
+		<version>0.15.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>forwarder</artifactId>
+	<name>Eingangs Adapter - Forwarder</name>
+	<packaging>jar</packaging>
+
+	<properties>
+		<spring-boot.build-image.imageName>docker.ozg-sh.de/forwarder:build-latest</spring-boot.build-image.imageName>
+	</properties>
+
+	<dependencies>
+		<!-- own projects -->
+		<dependency>
+			<groupId>de.itvsh.kop.eingangsadapter</groupId>
+			<artifactId>common</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>de.itvsh.kop.eingangsadapter</groupId>
+			<artifactId>router</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>de.itvsh.ozg.pluto</groupId>
+			<artifactId>pluto-interface</artifactId>
+		</dependency>
+
+		<!-- spring -->
+		<dependency>
+			<groupId>net.devh</groupId>
+			<artifactId>grpc-server-spring-boot-starter</artifactId>
+			<version>${grpc.spring-boot-starter.version}</version>
+		</dependency>
+
+		<!-- Tools -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+		</dependency>
+
+		<!-- Dev -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-devtools</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-configuration-processor</artifactId>
+			<optional>true</optional>
+		</dependency>
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+		</dependency>
+
+		<!-- Test -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+			<exclusions>
+				<exclusion>
+					<groupId>org.junit.vintage</groupId>
+					<artifactId>junit-vintage-engine</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+
+			<plugin>
+				<groupId>org.jacoco</groupId>
+				<artifactId>jacoco-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+</project>
\ No newline at end of file
diff --git a/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteria.java b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteria.java
new file mode 100644
index 0000000000000000000000000000000000000000..b73df0f572f650e8bc0288878da5f991fb807677
--- /dev/null
+++ b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteria.java
@@ -0,0 +1,15 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import java.util.Optional;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class RouteCriteria {
+
+	private Optional<String> gemeindeSchluessel;
+	private Optional<String> webserviceUrl;
+	private Optional<String> organisationseinheitenId;
+}
diff --git a/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteriaMapper.java b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteriaMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ac933c244f3fbd5a1d2e2926424c322741304d3
--- /dev/null
+++ b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteriaMapper.java
@@ -0,0 +1,18 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import java.util.Optional;
+
+import org.apache.commons.lang3.StringUtils;
+import org.mapstruct.Mapper;
+
+import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteCriteria;
+
+@Mapper
+interface RouteCriteriaMapper {
+
+	RouteCriteria fromGrpc(GrpcRouteCriteria grpcRouteCriteria);
+
+	default Optional<String> wrapWithOptional(String val) {
+		return Optional.ofNullable(StringUtils.trimToNull(val));
+	}
+}
diff --git a/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingGrpcService.java b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingGrpcService.java
new file mode 100644
index 0000000000000000000000000000000000000000..7528d602db6effbafc263421b9ebf2e4207543a7
--- /dev/null
+++ b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingGrpcService.java
@@ -0,0 +1,29 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingRequest;
+import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingResponse;
+import de.itvsh.kop.eingangsadapter.router.GrpcEingangMapper;
+import de.itvsh.kop.eingangsadapter.router.GrpcFormDataMapper;
+import io.grpc.stub.StreamObserver;
+import net.devh.boot.grpc.server.service.GrpcService;
+
+@GrpcService
+public class RouteForwardingGrpcService extends RouteForwardingServiceGrpc.RouteForwardingServiceImplBase {
+
+	@Autowired
+	private RouteForwardingService service;
+	@Autowired
+	private RouteCriteriaMapper criteriaMapper;
+
+	@Autowired
+	private GrpcEingangMapper eingangMapper;
+	@Autowired
+	private GrpcFormDataMapper formDataMapper;
+
+	@Override
+	public void routeForwarding(GrpcRouteForwardingRequest request, StreamObserver<GrpcRouteForwardingResponse> responseObserver) {
+		service.route(criteriaMapper.fromGrpc(request.getRouteCriteria()), formDataMapper.mapFromFormData(request.getE));
+	}
+}
diff --git a/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingService.java b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingService.java
new file mode 100644
index 0000000000000000000000000000000000000000..72fd540d5650e5f57ae28bbb177c3587267bd819
--- /dev/null
+++ b/forwarder/src/main/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingService.java
@@ -0,0 +1,13 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import org.springframework.stereotype.Service;
+
+import de.itvsh.kop.eingangsadapter.common.formdata.FormData;
+
+@Service
+class RouteForwardingService {
+
+	public void route(RouteCriteria criteria, FormData formData) {
+//FIXME implement me
+	}
+}
diff --git a/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/ForwarderApplicationTest.java b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/ForwarderApplicationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e70e325b98a36ab5758202c98eacfbd39a4571ad
--- /dev/null
+++ b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/ForwarderApplicationTest.java
@@ -0,0 +1,14 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import de.itvsh.kop.eingangsadapter.Application;
+
+@SpringBootTest(classes = Application.class)
+class ForwarderApplicationTest {
+
+	@Test
+	void contextLoads() { // NOSONAR nothing to check - it it starts it is fine
+	}
+}
diff --git a/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/GrpcRouteForwardingRequestTestFactory.java b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/GrpcRouteForwardingRequestTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef7d1d8d167f0d0ad4b3f9bc0d8f3c0d0c4d37fd
--- /dev/null
+++ b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/GrpcRouteForwardingRequestTestFactory.java
@@ -0,0 +1,15 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingRequest;
+
+public class GrpcRouteForwardingRequestTestFactory {
+
+	public static GrpcRouteForwardingRequest create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcRouteForwardingRequest.Builder createBuilder() {
+		return GrpcRouteForwardingRequest.newBuilder()
+				.setRouteCriteria(RouteCriteriaTestFactory.createGrpc());
+	}
+}
diff --git a/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteriaTestFactory.java b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteriaTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..309aaee624ffb3d4b69f4e780e903ff613e9d2a9
--- /dev/null
+++ b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/RouteCriteriaTestFactory.java
@@ -0,0 +1,34 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import java.util.Optional;
+
+import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteCriteria;
+
+public class RouteCriteriaTestFactory {
+
+	public static final String GEMEINDE_SCHLUSSEL = "0815";
+	public static final String WEBSERVICE_URL = "http://nimmerland.ozg-sh.de/ws";
+	public static final String ORGANISATIONSEINHEITEN_ID = "4711";
+
+	public static RouteCriteria create() {
+		return createBuilder().build();
+	}
+
+	public static RouteCriteria.RouteCriteriaBuilder createBuilder() {
+		return RouteCriteria.builder()
+				.gemeindeSchluessel(Optional.of(GEMEINDE_SCHLUSSEL))
+				.webserviceUrl(Optional.of(WEBSERVICE_URL))
+				.organisationseinheitenId(Optional.of(ORGANISATIONSEINHEITEN_ID));
+	}
+
+	public static GrpcRouteCriteria createGrpc() {
+		return createGrpcBuilder().build();
+	}
+
+	public static GrpcRouteCriteria.Builder createGrpcBuilder() {
+		return GrpcRouteCriteria.newBuilder()
+				.setGemeindeSchluessel(GEMEINDE_SCHLUSSEL)
+				.setWebserviceUrl(WEBSERVICE_URL)
+				.setOrganisationseinheitenId(ORGANISATIONSEINHEITEN_ID);
+	}
+}
diff --git a/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingGrpcServiceTest.java b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingGrpcServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3e2bd9a43a0213b94b3d40d237937835d68a2e0
--- /dev/null
+++ b/forwarder/src/test/java/de/itvsh/kop/eingangsadapter/forwarder/RouteForwardingGrpcServiceTest.java
@@ -0,0 +1,67 @@
+package de.itvsh.kop.eingangsadapter.forwarder;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import de.itvsh.kop.eingangsadapter.forwarding.GrpcRouteForwardingResponse;
+import de.itvsh.kop.eingangsadapter.router.GrpcEingangMapper;
+import de.itvsh.kop.eingangsadapter.router.GrpcFormDataMapper;
+import io.grpc.stub.StreamObserver;
+
+class RouteForwardingGrpcServiceTest {
+
+	@InjectMocks
+	private RouteForwardingGrpcService service;
+
+	@Mock
+	private StreamObserver<GrpcRouteForwardingResponse> responseObserver;
+
+	@Mock
+	private RouteForwardingService routeService;
+	@Spy
+	private RouteCriteriaMapper criteriaMapper = Mappers.getMapper(RouteCriteriaMapper.class);
+	@Spy
+	private GrpcEingangMapper eingangMapper; = Mappers.getMapper(GrpcEingangMapper.class);
+
+	@Nested
+	class TestRouteForwarding {
+
+		@Captor
+		private ArgumentCaptor<RouteCriteria> criteriaCaptor;
+
+		@Test
+		void shouldCallService() {
+			service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), responseObserver);
+
+			verify(routeService).route(any(), any());
+		}
+
+		@Test
+		void shouldHaveRouteCriteria() {
+			service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), responseObserver);
+
+			verify(routeService).route(criteriaCaptor.capture(), any());
+
+			assertThat(criteriaCaptor.getValue()).usingRecursiveComparison().isEqualTo(RouteCriteriaTestFactory.create());
+		}
+
+		@Test
+		void shouldHaveFormData() {
+			service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), responseObserver);
+
+			verify(routeService).route(any(), notNull());
+			verify(formDataMapper).mapToSubForms(any());
+		}
+	}
+
+}
diff --git a/forwarder/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/forwarder/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension
new file mode 100644
index 0000000000000000000000000000000000000000..79b126e6cdb86bec1f4f08c205de8961bde1934a
--- /dev/null
+++ b/forwarder/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension
@@ -0,0 +1 @@
+org.mockito.junit.jupiter.MockitoExtension
\ No newline at end of file
diff --git a/forwarder/src/test/resources/application-itcase.yml b/forwarder/src/test/resources/application-itcase.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/forwarder/src/test/resources/application.yml b/forwarder/src/test/resources/application.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9ffb14ed87f4ac5b56fa404756d22f9c1f5b62e7
--- /dev/null
+++ b/forwarder/src/test/resources/application.yml
@@ -0,0 +1,19 @@
+spring:
+  profiles:
+    active:
+    - itcase
+
+logging:
+  level:
+    ROOT: ERROR
+    
+grpc:
+  client:
+    pluto-nf:
+      address: static://127.0.0.1:9090
+      negotiationType: PLAINTEXT
+    
+kop:
+  adapter:
+    routingStrategy: SINGLE
+    targetPlutoName: nf
\ No newline at end of file
diff --git a/forwarder/src/test/resources/junit-platform.properties b/forwarder/src/test/resources/junit-platform.properties
new file mode 100644
index 0000000000000000000000000000000000000000..1cebb76d5a58ac034b2627d12411d82d1e85821e
--- /dev/null
+++ b/forwarder/src/test/resources/junit-platform.properties
@@ -0,0 +1 @@
+junit.jupiter.extensions.autodetection.enabled = true
\ No newline at end of file
diff --git a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FileReaderAntragDirectoryParser.java b/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FileReaderAntragDirectoryParser.java
index 86b7ce777fff41a923c8041e028a7bf7985965c9..d1128fc8c7b8c738f59f4cc381675c3c07704da4 100644
--- a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FileReaderAntragDirectoryParser.java
+++ b/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FileReaderAntragDirectoryParser.java
@@ -5,7 +5,6 @@ import java.io.InputStream;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -60,7 +59,6 @@ class FileReaderAntragDirectoryParser {
 		Map<String, Object> formDataMap = xmlToJavaMapsMapper.mapXmlToJavaMaps(document);
 
 		return FormData.builder()
-				.id(UUID.randomUUID())
 				.header(formHeaderMapper.map(document))
 				.antragsteller(antragstellerMapper.mapToAntragsteller(formDataMap))
 				.zustaendigeStelle(zustaendigeStelleMapper.map(formDataMap))
diff --git a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FormDataMapper.java b/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FormDataMapper.java
index b716fcbf080b9ebf841e922138b764199e0d3579..a0ce839b9f61974db50277292fb576e692baebb9 100644
--- a/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FormDataMapper.java
+++ b/intelliform-adapter/src/main/java/de/itvsh/kop/eingangsadapter/intelliform/FormDataMapper.java
@@ -3,7 +3,6 @@ package de.itvsh.kop.eingangsadapter.intelliform;
 import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -52,7 +51,6 @@ class FormDataMapper {
 		formDataFiles = attachmentsContentAdder.addContentToAttachments(formDataFiles, depositRequestFiles);
 
 		return FormData.builder()
-				.id(UUID.randomUUID())
 				.header(formHeaderMapper.map(document))
 				.antragsteller(antragstellerMapper.mapToAntragsteller(formDataMap))
 				.zustaendigeStelle(zustaendigeStelleMapper.map(formDataMap))
diff --git a/pom.xml b/pom.xml
index ad5d8b06d06aa49623ae802223027cf7919a7ed2..9c05321e8846060dfd7928581de5606619caeaeb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,7 @@
 		<module>formsolutions-adapter</module>
 		<module>intelliform-adapter</module>
 		<module>router</module>
+		<module>forwarder</module>
 	</modules>
 
 	<properties>
diff --git a/router/pom.xml b/router/pom.xml
index 6feb8b32bda830a28bad80fe30a134a8d6168322..edc1523b51aabc6d4360c8a4c8edb84ab31e1009 100644
--- a/router/pom.xml
+++ b/router/pom.xml
@@ -32,6 +32,13 @@
 			<artifactId>spring-boot-configuration-processor</artifactId>
 			<optional>true</optional>
 		</dependency>
+		
+		<!-- Tools -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+		</dependency>
+		
 
 		<!-- Test -->
 		<dependency>
diff --git a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapper.java b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapper.java
index 6392ee27dbef05dfebb07385ddd70af537d0b13f..7c43018f2b18a945b93168bd6b3d645fd9dc25e9 100644
--- a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapper.java
+++ b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapper.java
@@ -25,7 +25,7 @@ import de.itvsh.ozg.pluto.vorgang.GrpcZustaendigeStelle;
 		nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, //
 		collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, //
 		uses = GrpcFormDataMapper.class)
-interface GrpcEingangMapper {
+public interface GrpcEingangMapper {
 
 	@Mapping(source = "antragsteller.data", target = "antragsteller.otherData")
 	@Mapping(source = "attachments", target = "attachmentsList")
@@ -51,4 +51,11 @@ interface GrpcEingangMapper {
 		return id.toString();
 	}
 
+	// FIXME map representations and attachments
+	@Mapping(target = "attachment", ignore = true)
+	@Mapping(target = "attachments", ignore = true)
+	@Mapping(target = "representation", ignore = true)
+	@Mapping(target = "representations", ignore = true)
+	FormData toFormData(GrpcEingang eingang);
+
 }
diff --git a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapper.java b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapper.java
index 8ba41ad35fddff3dbbc7f22292cb09dcfe9852ac..685746b090fb39bfba9ea537e1a3cc96eb5314c1 100644
--- a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapper.java
+++ b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapper.java
@@ -1,10 +1,15 @@
 package de.itvsh.kop.eingangsadapter.router;
 
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.mapstruct.CollectionMappingStrategy;
 import org.mapstruct.Mapper;
 import org.mapstruct.NullValueCheckStrategy;
@@ -20,7 +25,7 @@ import de.itvsh.ozg.pluto.vorgang.GrpcSubForm;
 		nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, //
 		nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, //
 		collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
-interface GrpcFormDataMapper {
+public interface GrpcFormDataMapper {
 
 	default GrpcFormData mapFormData(Map<String, Object> formData) {
 		return GrpcFormData.newBuilder()
@@ -89,4 +94,92 @@ interface GrpcFormDataMapper {
 	default GrpcFormField mapToField(String name, String value) {
 		return GrpcFormField.newBuilder().setName(name).setValue(value).build();
 	}
+
+	// TODO copied from de.itvsh.ozg.pluto.vorgang.GrpcFormDataMapper
+	// move to mapper util lib (OZG-1517)
+	default Map<String, Object> mapFromFormData(GrpcFormData formData) {
+		Map<String, Object> result = new HashMap<>();
+		result.putAll(mapSubFormFields(formData.getFieldList()));
+		result.putAll(mapFormData(formData.getFormList()));
+		return result;
+	}
+
+	default Map<String, Object> mapFormData(List<GrpcSubForm> subForms) {
+		return subForms.stream().map(subForm -> Pair.of(subForm.getTitle(), mapSubForm(subForm)))
+				.collect(HashMap<String, Object>::new, this::pairAccumulator, this::combiner);
+	}
+
+	private Map<String, Object> pairAccumulator(Map<String, Object> map, Pair<String, Map<String, Object>> pair) {
+		return addToMap(map, pair.getLeft(), pair.getRight());
+	}
+
+	default Map<String, Object> mapSubForm(GrpcSubForm subForm) {
+		Map<String, Object> result = new HashMap<>();
+		result.putAll(mapSubFormFields(subForm.getFieldList()));
+		result.putAll(mapFormData(subForm.getSubFormList()));
+		return result;
+	}
+
+	default Map<String, Object> mapSubFormFields(List<GrpcFormField> fields) {
+		return fields.stream().collect(HashMap<String, Object>::new, this::accumulator, this::combiner);
+	}
+
+	private Map<String, Object> accumulator(Map<String, Object> map, GrpcFormField field) {
+		return addToMap(map, field.getName(), field.getValue());
+	}
+
+	default Map<String, Object> combiner(Map<String, Object> map1, Map<String, Object> map2) {
+		for (Entry<String, Object> entry : map2.entrySet()) {
+			addToMap(map1, entry.getKey(), entry.getValue());
+		}
+
+		return map1;
+	}
+
+	@SuppressWarnings("unchecked")
+	private Map<String, Object> addToMap(Map<String, Object> map, String name, Object value) {
+		var valueInMap = map.get(name);
+		if (Objects.isNull(valueInMap)) {
+			map.put(name, value);
+		} else {
+			if (value instanceof Collection) {
+				addCollectionValue(map, name, (Collection<Object>) value);
+			} else {
+				addNonCollectionValue(map, name, value);
+			}
+		}
+
+		return map;
+	}
+
+	@SuppressWarnings("unchecked")
+	private Map<String, Object> addCollectionValue(Map<String, Object> map, String name, Collection<Object> value) {
+		var valueInMap = map.get(name);
+
+		var newList = new LinkedList<Object>();
+		if (valueInMap instanceof Collection) {
+			newList.addAll((Collection<? extends Object>) valueInMap);
+			newList.addAll(value);
+		} else {
+			newList.add(valueInMap);
+			newList.addAll(value);
+		}
+		map.put(name, newList);
+		return map;
+	}
+
+	@SuppressWarnings("unchecked")
+	private Map<String, Object> addNonCollectionValue(Map<String, Object> map, String name, Object value) {
+		var valueInMap = map.get(name);
+
+		if (valueInMap instanceof Collection) {
+			var newList = new LinkedList<>((Collection<Object>) valueInMap);
+			newList.add(value);
+			map.put(name, newList);
+		} else {
+			map.put(name, new LinkedList<>(List.of(valueInMap, value)));
+		}
+
+		return map;
+	}
 }
diff --git a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/VorgangRemoteService.java b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/VorgangRemoteService.java
index 4daa6ba9c494d5277828b8b4e6744d7d6d987cfe..4e8a3873bce71ce06b925cb15a1e1c9938f078c0 100644
--- a/router/src/main/java/de/itvsh/kop/eingangsadapter/router/VorgangRemoteService.java
+++ b/router/src/main/java/de/itvsh/kop/eingangsadapter/router/VorgangRemoteService.java
@@ -5,6 +5,7 @@ import java.util.Optional;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import de.itvsh.kop.eingangsadapter.common.formdata.FormData;
 import de.itvsh.ozg.pluto.vorgang.GrpcCreateVorgangRequest;
 import de.itvsh.ozg.pluto.vorgang.GrpcEingang;
 import de.itvsh.ozg.pluto.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub;
@@ -17,10 +18,16 @@ public class VorgangRemoteService {
 	@Autowired
 	private PlutoServerResolver plutoServerResolver;
 
+	@Deprecated
 	public String createVorgang(GrpcEingang eingang, Optional<String> organisationsEinheitId) {
 		VorgangServiceBlockingStub plutoStub = plutoServerResolver.resolveOrganisationsEinheitId(organisationsEinheitId);
 		LOG.info("Connecting to pluto server " + plutoStub.getChannel().authority() + "; OrganisationsEinheitId: " + organisationsEinheitId);
 
 		return plutoStub.createVorgang(GrpcCreateVorgangRequest.newBuilder().setEingang(eingang).build()).getMessage();
 	}
+
+	public String createVorgang(FormData formData, VorgangServiceBlockingStub remoteStub) {
+		// FIXME emplement me
+		return null;
+	}
 }
diff --git a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapperTest.java b/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapperTest.java
index 98416c77df915f8dbeb9f262566eb743477e2831..76bb1666656a787e39509d86dae12fe83df6a62c 100644
--- a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapperTest.java
+++ b/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcEingangMapperTest.java
@@ -31,7 +31,7 @@ class GrpcEingangMapperTest {
 
 	@BeforeEach
 	void mockMapperReturnValues() {
-		lenient().when(grpcFormDataMapper.mapFormData(any()))
+		lenient().when(grpcFormDataMapper.mapFormData(anyMap()))
 				.thenReturn(GrpcFormData.newBuilder().addField(GrpcFormFieldTestFactory.create()).build());
 	}
 
diff --git a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapperTest.java b/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapperTest.java
index cb4dd46ec9f465973177e9b1cec00192d41becf0..dd92cd280bc3cc4a62af6abcc0b12d0d3956c5f2 100644
--- a/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapperTest.java
+++ b/router/src/test/java/de/itvsh/kop/eingangsadapter/router/GrpcFormDataMapperTest.java
@@ -29,7 +29,7 @@ class GrpcFormDataMapperTest {
 
 	@BeforeEach
 	void mockMapperReturnValues() {
-		lenient().when(grpcFormDataMapper.mapFormData(any()))
+		lenient().when(grpcFormDataMapper.mapFormData(anyMap()))
 				.thenReturn(GrpcFormData.newBuilder().addField(GrpcFormFieldTestFactory.create()).build());
 	}