diff --git a/api-lib-core/pom.xml b/api-lib-core/pom.xml
index cd3f0432cb5d1da8623e27574e79b46dbdb8f0f1..ad3c80c88e0e254934a24ce5f268b97c45b3328e 100644
--- a/api-lib-core/pom.xml
+++ b/api-lib-core/pom.xml
@@ -9,6 +9,11 @@
 	</parent>
 
 	<artifactId>api-lib-core</artifactId>
+	
+	<properties>
+		<lombok.version>1.18.26</lombok.version>
+		<mapstruct.version>1.5.4.Final</mapstruct.version>
+	</properties>
 
 	<dependencies>
 		<!--ozg cloud project -->
@@ -22,6 +27,43 @@
 			<artifactId>spring-context</artifactId>
 		</dependency>
 
+		<dependency>
+			<groupId>de.itvsh.ozg.pluto</groupId>
+			<artifactId>pluto-interface</artifactId>
+		</dependency>
+
+		<!--spring -->
+		<dependency>
+			<groupId>net.devh</groupId>
+			<artifactId>grpc-client-spring-boot-starter</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.mapstruct</groupId>
+			<artifactId>mapstruct</artifactId>
+		</dependency>
+
+		<!-- test -->
+		<dependency>
+			<groupId>org.junit.jupiter</groupId>
+			<artifactId>junit-jupiter</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.assertj</groupId>
+			<artifactId>assertj-core</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-core</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-junit-jupiter</artifactId>
+			<scope>test</scope>
+		</dependency>
+
 		<!--dev-tools -->
 		<dependency>
 			<groupId>org.projectlombok</groupId>
@@ -30,4 +72,40 @@
 			<optional>true</optional>
 		</dependency>
 	</dependencies>
+	
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.10.1</version>
+				<configuration>
+					<fork>true</fork>
+					<annotationProcessorPaths>
+						<path>
+							<groupId>org.projectlombok</groupId>
+							<artifactId>lombok</artifactId>
+							<version>${lombok.version}</version>
+						</path>
+						<path>
+							<groupId>org.mapstruct</groupId>
+							<artifactId>mapstruct-processor</artifactId>
+							<version>${mapstruct.version}</version>
+						</path>
+						<!-- other annotation processors -->
+					</annotationProcessorPaths>
+
+					<showWarnings>true</showWarnings>
+					<compilerArgs>
+						<compilerArg>
+							-Amapstruct.defaultComponentModel=spring
+						</compilerArg>
+						<compilerArg>
+							-Amapstruct.unmappedTargetPolicy=WARN
+						</compilerArg>
+					</compilerArgs>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
 </project>
\ No newline at end of file
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/user/UserId.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/user/UserId.java
index 72013e49dbfbc8a3ac7d03d53e84da87c4611da2..a8d4e3f4a28f84a2c2d08c8d4256e1fdbaf01f50 100644
--- a/api-lib-core/src/main/java/de/ozgcloud/apilib/user/UserId.java
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/user/UserId.java
@@ -7,4 +7,8 @@ public class UserId extends StringBasedValue {
 	UserId(String id) {
 		super(id);
 	}
+
+	public static UserId from(String id) {
+		return new UserId(id);
+	}
 }
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudAntragsteller.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudAntragsteller.java
index 2e0c91e0cb1ad31532617eb9974b290c14bc82cc..bd3fbb49799a0a98829077274307a9f8ea05bc3c 100644
--- a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudAntragsteller.java
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudAntragsteller.java
@@ -7,20 +7,31 @@ import lombok.Getter;
 @Builder
 public class OzgCloudAntragsteller {
 
+	/** Salutation */
 	private String anrede;
-	private String nachname;
+	/** Firstname */
 	private String vorname;
+	/** Lastname */
+	private String nachname;
 
+	/** Day of birth */
 	private String geburtsdatum;
+	/** City of birth */
 	private String geburtsort;
+	/** Name of birth */
 	private String geburtsname;
 
+	/** Street */
 	private String strasse;
+	/** House Number */
 	private String hausnummer;
+	/** postcode / Zip Code */
 	private String plz;
+	/** City */
 	private String ort;
 
 	private String email;
+	/** Telephone number */
 	private String telefon;
 
 }
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudEingangHeader.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudEingangHeader.java
index db38759bf5f2521ac972828c7baa5fb6f7b42bf1..c7dfbac0705981f6b5a101d4b9c90b2e70216a4e 100644
--- a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudEingangHeader.java
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudEingangHeader.java
@@ -17,8 +17,4 @@ public class OzgCloudEingangHeader {
 	private String formId;
 	private String formName;
 	private String formEngineName;
-
-	private String sender;
-	@ToString.Exclude
-	private OzgCloudServiceKonto serviceKonto;
 }
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudServiceKontoType.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudServiceKontoType.java
index f81c4bca58dafe737031c21db6da1460b35e6112..a477cb4086315ccc1ed9edbc8016002f8483889f 100644
--- a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudServiceKontoType.java
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudServiceKontoType.java
@@ -4,4 +4,11 @@ import de.itvsh.kop.common.datatype.StringBasedValue;
 
 public class OzgCloudServiceKontoType extends StringBasedValue {
 
+	OzgCloudServiceKontoType(String type) {
+		super(type);
+	}
+
+	public static OzgCloudServiceKontoType from(String type) {
+		return new OzgCloudServiceKontoType(type);
+	}
 }
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudSubForm.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudSubForm.java
index 7e3a86a8462e47ddf6f4862f892e43d18d934aae..dbd13268716c3a718f35b3db2861f32b31e2cb20 100644
--- a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudSubForm.java
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudSubForm.java
@@ -1,7 +1,10 @@
 package de.ozgcloud.apilib.vorgang;
 
+import java.util.List;
+
 import lombok.Builder;
 import lombok.Getter;
+import lombok.Singular;
 
 @Getter
 @Builder
@@ -9,6 +12,8 @@ public class OzgCloudSubForm implements OzgCloudFormDataEntry {
 
 	private String name;
 	private String label;
+	@Singular
+	private List<OzgCloudFormDataEntry> formEntrys;
 
 	@Override
 	public boolean isSubForm() {
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgang.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgang.java
index 70cd0d81a6208daeab283441c1a391abbfe3abff..a04a80265c19c01c37a9308296a68f9267bce8d7 100644
--- a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgang.java
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgang.java
@@ -17,6 +17,7 @@ public class OzgCloudVorgang {
 	private String vorgangNummer;
 
 	private OzgCloudVorgangHeader header;
+
 	@Singular
 	private List<OzgCloudEingang> eingangs;
 }
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangHeader.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangHeader.java
index beda8ed89ee1020c56c09ed27bad2f30b377c156..a6af8c35a0046752ba002ba8ecfa98bcdd374b0c 100644
--- a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangHeader.java
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangHeader.java
@@ -5,6 +5,7 @@ import java.time.ZonedDateTime;
 import de.ozgcloud.apilib.user.UserId;
 import lombok.Builder;
 import lombok.Getter;
+import lombok.ToString;
 
 @Builder
 @Getter
@@ -14,7 +15,10 @@ public class OzgCloudVorgangHeader {
 
 	private ZonedDateTime createdAt;
 
-	private UserId assigendTo;
+	private UserId assignedTo;
 
 	private String aktenzeichen;
+
+	@ToString.Exclude
+	private OzgCloudServiceKonto serviceKonto;
 }
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangService.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab96c7ece5ce9aea2fd0e0fdd94285ba0fc47d38
--- /dev/null
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangService.java
@@ -0,0 +1,43 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import java.util.List;
+
+import org.springframework.stereotype.Service;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcFindVorgangWithEingangRequest;
+import de.itvsh.ozg.pluto.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgang;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStub;
+import lombok.NonNull;
+import net.devh.boot.grpc.client.inject.GrpcClient;
+
+@Service
+class GrpcVorgangService implements OzgCloudVorgangService {
+
+	@GrpcClient("vorgang-manager")
+	private VorgangServiceBlockingStub vorgangServiceStub;
+
+	private OzgCloudVorgangMapper mapper;
+
+	@Override
+	public OzgCloudVorgang getById(@NonNull OzgCloudVorgangId vorgangId) {
+		var response = vorgangServiceStub.findVorgangWithEingang(buildRequest(vorgangId));
+
+		return mapper.fromGrpc(response.getVorgangWithEingang());
+	}
+
+	private GrpcFindVorgangWithEingangRequest buildRequest(@NonNull OzgCloudVorgangId vorgangId) {
+		return GrpcFindVorgangWithEingangRequest.newBuilder()
+				.setId(vorgangId.toString())
+				.build();
+	}
+
+	@Override
+	public List<OzgCloudVorgangStub> search(@NonNull String searchString) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudEingangMapper.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudEingangMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..f024d80522b31d0859d2437b491e709ea198395b
--- /dev/null
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudEingangMapper.java
@@ -0,0 +1,48 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcEingang;
+import de.itvsh.ozg.pluto.vorgang.GrpcFormData;
+import de.itvsh.ozg.pluto.vorgang.GrpcFormField;
+import de.itvsh.ozg.pluto.vorgang.GrpcSubForm;
+import de.ozgcloud.apilib.vorgang.OzgCloudEingang;
+import de.ozgcloud.apilib.vorgang.OzgCloudFormDataEntry;
+import de.ozgcloud.apilib.vorgang.OzgCloudFormField;
+import de.ozgcloud.apilib.vorgang.OzgCloudSubForm;
+
+@Mapper
+public interface OzgCloudEingangMapper {
+
+	// TODO map files
+	@Mapping(target = "attachments", ignore = true)
+	@Mapping(target = "representations", ignore = true)
+	@Mapping(target = "formDataEntrys", source = "formData")
+	@Mapping(target = "zustaendigeStelle.organisationsEinheitId", source = "zustaendigeStelle.organisationseinheitenId")
+	OzgCloudEingang fromGrpc(GrpcEingang eingang);
+
+	default List<OzgCloudFormDataEntry> mapFormData(GrpcFormData value) {
+		var fields = value.getFieldList().stream().map(this::fromGrpc);
+		var subForms = value.getFormList().stream().map(this::fromGrpc);
+
+		return Stream.concat(fields, subForms).toList();
+	}
+
+	OzgCloudFormField fromGrpc(GrpcFormField field);
+
+	@Mapping(target = "formEntry", ignore = true)
+	@Mapping(target = "formEntrys", source = "subForm")
+	@Mapping(target = "name", source = "title")
+	OzgCloudSubForm fromGrpc(GrpcSubForm subForm);
+
+	default List<OzgCloudFormDataEntry> mapSubForm(GrpcSubForm subForm) {
+		var fields = subForm.getFieldList().stream().map(this::fromGrpc);
+		var subForms = subForm.getSubFormList().stream().map(this::fromGrpc);
+
+		return Stream.concat(fields, subForms).toList();
+	}
+}
diff --git a/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudVorgangMapper.java b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudVorgangMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab983e0b6d8525c6ae64643cd8c9537020365094
--- /dev/null
+++ b/api-lib-core/src/main/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudVorgangMapper.java
@@ -0,0 +1,42 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import java.util.Optional;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcVorgangWithEingang;
+import de.ozgcloud.apilib.user.UserId;
+import de.ozgcloud.apilib.vorgang.OzgCloudServiceKontoType;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgang;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
+import de.ozgcloud.apilib.vorgang.VorgangStatus;
+
+@Mapper(uses = OzgCloudEingangMapper.class)
+public interface OzgCloudVorgangMapper {
+
+	@Mapping(target = "eingangs", ignore = true)
+	@Mapping(target = "vorgangNummer", source = "nummer")
+	@Mapping(target = "vorgangName", source = "name")
+	@Mapping(target = "header.aktenzeichen", source = "aktenzeichen")
+	@Mapping(target = "header.assignedTo", source = "assignedTo")
+	@Mapping(target = "header.createdAt", source = "createdAt")
+	@Mapping(target = "header.status", source = "status")
+	OzgCloudVorgang fromGrpc(GrpcVorgangWithEingang response);
+
+	default OzgCloudServiceKontoType toOzgCloudServiceKontoType(String type) {
+		return Optional.ofNullable(type).map(OzgCloudServiceKontoType::from).orElse(null);
+	}
+
+	default OzgCloudVorgangId toOzgCloudVorgangId(String vorgangId) {
+		return Optional.ofNullable(vorgangId).map(OzgCloudVorgangId::from).orElse(null);
+	}
+
+	default UserId toUserId(String userId) {
+		return Optional.ofNullable(userId).map(UserId::from).orElse(null);
+	}
+
+	default VorgangStatus toVorgangId(String status) {
+		return Optional.ofNullable(status).map(VorgangStatus::from).orElse(null);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudAntragstellerTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudAntragstellerTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb7c115d426b697674f03aabc796cbc604bff60f
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudAntragstellerTestFactory.java
@@ -0,0 +1,38 @@
+package de.ozgcloud.apilib.vorgang;
+
+public class OzgCloudAntragstellerTestFactory {
+
+	public static final String ANREDE = "Mr.";
+
+	public static final String FIRSTNAME = "Theo";
+	public static final String NACHNAME = "Test";
+	public static final String GEBURTSDATUM = "10.04.1995";
+	public static final String GEBURTSORT = "Downtown";
+	public static final String GEBURTSNAME = "Toast";
+	public static final String STRASSE = "Treestreet";
+	public static final String HAUSNUMMER = "5a";
+	public static final String PLZ = "12345";
+	public static final String ORT = "City";
+	public static final String E_MAIL = "test@local";
+	public static final String TELEFON = "0123 2354 546";
+
+	public static OzgCloudAntragsteller create() {
+		return createBuilder().build();
+	}
+
+	public static OzgCloudAntragsteller.OzgCloudAntragstellerBuilder createBuilder() {
+		return OzgCloudAntragsteller.builder()
+				.anrede(ANREDE)
+				.vorname(FIRSTNAME)
+				.nachname(NACHNAME)
+				.geburtsdatum(GEBURTSDATUM)
+				.geburtsort(GEBURTSORT)
+				.geburtsname(GEBURTSNAME)
+				.strasse(STRASSE)
+				.hausnummer(HAUSNUMMER)
+				.plz(PLZ)
+				.ort(ORT)
+				.email(E_MAIL)
+				.telefon(TELEFON);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudEingangHeaderTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudEingangHeaderTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..e72f225d32e9f097d1b99f5e009de2c716a93550
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudEingangHeaderTestFactory.java
@@ -0,0 +1,27 @@
+package de.ozgcloud.apilib.vorgang;
+
+import java.time.ZonedDateTime;
+
+public class OzgCloudEingangHeaderTestFactory {
+
+	public static final String REQUEST_ID = OzgCloudVorgangTestFactory.VORGANG_NAME;
+
+	public static final String CREATED_AT_STR = "2023-04-02T15:00:30Z";
+	public static final ZonedDateTime CREATED_AT = ZonedDateTime.parse(CREATED_AT_STR);
+	public static final String FORM_ID = "4177";
+	public static final String FORM_NAME = OzgCloudVorgangTestFactory.VORGANG_NAME;
+	public static final String FORM_ENGINE_NAME = "AFM";
+
+	public static OzgCloudEingangHeader create() {
+		return createBuilder().build();
+	}
+
+	public static OzgCloudEingangHeader.OzgCloudEingangHeaderBuilder createBuilder() {
+		return OzgCloudEingangHeader.builder()
+				.requestId(REQUEST_ID)
+				.createdAt(CREATED_AT)
+				.formId(FORM_ID)
+				.formName(FORM_NAME)
+				.formEngineName(FORM_ENGINE_NAME);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangEingangTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangEingangTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6b1a8070662b59837a83e7126edec6744753394
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangEingangTestFactory.java
@@ -0,0 +1,35 @@
+package de.ozgcloud.apilib.vorgang;
+
+import java.util.List;
+
+public class OzgCloudVorgangEingangTestFactory {
+
+	public static final String FIELD_NAME = "firstname";
+	public static final String FIELD_LABEL = "Firstname";
+	public static final String FIELD_VALUE = "Klaus";
+
+	public static final String SUB_FORM_NAME = "address";
+	public static final String SUB_FORM_LABEL = "Address";
+	public static final String SUB_FORM_FIELD_NAME = "street";
+	public static final String SUB_FORM_FIELD_LABEL = "Street";
+	public static final String SUB_FORM_FIELD_VALUE = "Mainstreet 5";
+
+	public static OzgCloudEingang create() {
+		return createBuilder().build();
+	}
+
+	public static OzgCloudEingang.OzgCloudEingangBuilder createBuilder() {
+		return OzgCloudEingang.builder()
+				.header(OzgCloudEingangHeaderTestFactory.create())
+				.antragsteller(OzgCloudAntragstellerTestFactory.create())
+				.zustaendigeStelle(OzgCloudZustaendigeStelleTestFactory.create())
+				.formDataEntrys(List.<OzgCloudFormDataEntry>of(
+						OzgCloudFormField.builder().name(FIELD_NAME).label(FIELD_LABEL).value(FIELD_VALUE).build(),
+						OzgCloudSubForm.builder().name(SUB_FORM_NAME).label(SUB_FORM_LABEL)
+								.formEntry(OzgCloudFormField.builder()
+										.name(SUB_FORM_FIELD_NAME)
+										.label(SUB_FORM_FIELD_LABEL)
+										.value(SUB_FORM_FIELD_VALUE).build())
+								.build()));
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangHeaderTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangHeaderTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..94a01f745ce2139755b3a23cbd8fb8b837df3505
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangHeaderTestFactory.java
@@ -0,0 +1,27 @@
+package de.ozgcloud.apilib.vorgang;
+
+import java.time.ZonedDateTime;
+import java.util.UUID;
+
+import de.ozgcloud.apilib.user.UserId;
+
+public class OzgCloudVorgangHeaderTestFactory {
+
+	public static VorgangStatus STATUS = VorgangStatus.from("WORKING");
+	public static String CREATED_AT_STR = "2023-04-01T10:00:15Z";
+	public static ZonedDateTime CREATED_AT = ZonedDateTime.parse(CREATED_AT_STR);
+	public static UserId ASSIGNED_TO = UserId.from(UUID.randomUUID().toString());
+	public static String AKTENZEICHEN = "DE_12345_XY";
+
+	public static OzgCloudVorgangHeader create() {
+		return createBuilder().build();
+	}
+
+	public static OzgCloudVorgangHeader.OzgCloudVorgangHeaderBuilder createBuilder() {
+		return OzgCloudVorgangHeader.builder()
+				.status(STATUS)
+				.createdAt(CREATED_AT)
+				.assignedTo(ASSIGNED_TO)
+				.aktenzeichen(AKTENZEICHEN);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9964bd4a1c97786f4f105965844c679f8bfb870
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudVorgangTestFactory.java
@@ -0,0 +1,25 @@
+package de.ozgcloud.apilib.vorgang;
+
+import java.util.UUID;
+
+public class OzgCloudVorgangTestFactory {
+
+	public static final OzgCloudVorgangId ID = OzgCloudVorgangId.from(UUID.randomUUID().toString());
+	public static final long VERSION = 42L;
+
+	public static final String VORGANG_NAME = "Antrag auf Waffelschein";
+	public static final String VORGANG_NUMMER = "123-abc-XY";
+
+	public static OzgCloudVorgang create() {
+		return createBuilder().build();
+	}
+
+	public static OzgCloudVorgang.OzgCloudVorgangBuilder createBuilder() {
+		return OzgCloudVorgang.builder()
+				.id(ID)
+				.version(VERSION)
+				.vorgangName(VORGANG_NAME)
+				.vorgangNummer(VORGANG_NUMMER)
+				.header(OzgCloudVorgangHeaderTestFactory.create());
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudZustaendigeStelleTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudZustaendigeStelleTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d895159e9718ef70624f38eef101e46ece5ae3d8
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/OzgCloudZustaendigeStelleTestFactory.java
@@ -0,0 +1,19 @@
+package de.ozgcloud.apilib.vorgang;
+
+public class OzgCloudZustaendigeStelleTestFactory {
+
+	public static final String ORGANISATIONS_EINHEIT_ID = "12345";
+	public static final String BEZEICHNUNG = "Amt für Dinge";
+	public static final String EMAIL = "amt@local";
+
+	public static OzgCloudZustaendigeStelle create() {
+		return createBuilder().build();
+	}
+
+	public static OzgCloudZustaendigeStelle.OzgCloudZustaendigeStelleBuilder createBuilder() {
+		return OzgCloudZustaendigeStelle.builder()
+				.organisationsEinheitId(ORGANISATIONS_EINHEIT_ID)
+				.bezeichnung(BEZEICHNUNG)
+				.email(EMAIL);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcAntragstellerTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcAntragstellerTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..12f786052323bbf90e358e0b0b8b2229e3130837
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcAntragstellerTestFactory.java
@@ -0,0 +1,28 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import static de.ozgcloud.apilib.vorgang.OzgCloudAntragstellerTestFactory.*;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcAntragsteller;
+
+public class GrpcAntragstellerTestFactory {
+
+	public static GrpcAntragsteller create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcAntragsteller.Builder createBuilder() {
+		return GrpcAntragsteller.newBuilder()
+				.setAnrede(ANREDE)
+				.setVorname(FIRSTNAME)
+				.setNachname(NACHNAME)
+				.setGeburtsdatum(GEBURTSDATUM)
+				.setGeburtsort(GEBURTSORT)
+				.setGeburtsname(GEBURTSNAME)
+				.setStrasse(STRASSE)
+				.setHausnummer(HAUSNUMMER)
+				.setPlz(PLZ)
+				.setOrt(ORT)
+				.setEmail(E_MAIL)
+				.setTelefon(TELEFON);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcEingangHeaderTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcEingangHeaderTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..50c6c6304734573487d3a29d12e7d378771cbb1e
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcEingangHeaderTestFactory.java
@@ -0,0 +1,21 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import static de.ozgcloud.apilib.vorgang.OzgCloudEingangHeaderTestFactory.*;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcEingangHeader;
+
+public class GrpcEingangHeaderTestFactory {
+
+	public static GrpcEingangHeader create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcEingangHeader.Builder createBuilder() {
+		return GrpcEingangHeader.newBuilder()
+				.setRequestId(REQUEST_ID)
+				.setCreatedAt(CREATED_AT_STR)
+				.setFormId(FORM_ID)
+				.setFormName(FORM_NAME)
+				.setFormEngineName(FORM_ENGINE_NAME);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcEingangTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcEingangTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..f98076bf623e88e31c0175ca6f7a8d2355b0a37b
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcEingangTestFactory.java
@@ -0,0 +1,34 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import static de.ozgcloud.apilib.vorgang.OzgCloudVorgangEingangTestFactory.*;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcEingang;
+import de.itvsh.ozg.pluto.vorgang.GrpcFormData;
+import de.itvsh.ozg.pluto.vorgang.GrpcFormField;
+import de.itvsh.ozg.pluto.vorgang.GrpcSubForm;
+
+public class GrpcEingangTestFactory {
+
+	public static GrpcEingang create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcEingang.Builder createBuilder() {
+		return GrpcEingang.newBuilder()
+				.setHeader(GrpcEingangHeaderTestFactory.create())
+				.setAntragsteller(GrpcAntragstellerTestFactory.create())
+				.setZustaendigeStelle(GrpcZustaendigeStelleTestFactory.create())
+				.setFormData(createFormData());
+	}
+
+	public static GrpcFormData createFormData() {
+		return GrpcFormData.newBuilder()
+				.addField(GrpcFormField.newBuilder().setName(FIELD_NAME).setLabel(FIELD_LABEL).setValue(FIELD_VALUE).build())
+				.addForm(GrpcSubForm.newBuilder().setTitle(SUB_FORM_NAME).setLabel(SUB_FORM_LABEL)
+						.addField(GrpcFormField.newBuilder()
+								.setName(SUB_FORM_FIELD_NAME)
+								.setLabel(SUB_FORM_FIELD_LABEL)
+								.setValue(SUB_FORM_FIELD_VALUE).build()))
+				.build();
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcFindVorgangWithEingangResponseTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcFindVorgangWithEingangResponseTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..21beecc999f60227fe6b80ec560f6ea5dedb9145
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcFindVorgangWithEingangResponseTestFactory.java
@@ -0,0 +1,15 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcFindVorgangWithEingangResponse;
+
+public class GrpcFindVorgangWithEingangResponseTestFactory {
+
+	public static GrpcFindVorgangWithEingangResponse create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcFindVorgangWithEingangResponse.Builder createBuilder() {
+		return GrpcFindVorgangWithEingangResponse.newBuilder()
+				.setVorgangWithEingang(GrpcVorgangWithEingangTestFactory.create());
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcServiceKontoTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcServiceKontoTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9d629886df068b06f1911d89c69b38a2b0136618
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcServiceKontoTestFactory.java
@@ -0,0 +1,26 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import de.itvsh.ozg.pluto.common.GrpcObject;
+import de.itvsh.ozg.pluto.common.GrpcProperty;
+import de.itvsh.ozg.pluto.vorgang.GrpcPostfachAddress;
+import de.itvsh.ozg.pluto.vorgang.GrpcServiceKonto;
+
+public class GrpcServiceKontoTestFactory {
+
+	public static final String TYPE = "OSI";
+	public static final String VERSION = "1.0";
+
+	public static GrpcServiceKonto create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcServiceKonto.Builder createBuilder() {
+		return GrpcServiceKonto.newBuilder()
+				.setType(TYPE)
+				.addPostfachAddresses(GrpcPostfachAddress.newBuilder()
+						.setVersion(VERSION)
+						.setIdentifier(GrpcObject.newBuilder().addProperty(GrpcProperty.newBuilder()
+								.setName("postfachId").addValue("0815").build())));
+	}
+
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangHeadTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangHeadTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..39f067719cf6ec0812636c28a48c6be81cf3ad1f
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangHeadTestFactory.java
@@ -0,0 +1,15 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcVorgangHead;
+
+public class GrpcVorgangHeadTestFactory {
+
+	public static GrpcVorgangHead create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcVorgangHead.Builder createBuilder() {
+		return GrpcVorgangHead.newBuilder()
+				.setServiceKonto(GrpcServiceKontoTestFactory.create());
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangServiceTest.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4deb49f7a9139e12893b3349b9d7a08aafc99bf4
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangServiceTest.java
@@ -0,0 +1,72 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+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.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.itvsh.ozg.pluto.vorgang.GrpcFindVorgangWithEingangRequest;
+import de.itvsh.ozg.pluto.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory;
+
+class GrpcVorgangServiceTest {
+
+	@InjectMocks
+	private GrpcVorgangService service;
+
+	@Mock
+	private VorgangServiceBlockingStub stub;
+	@Mock
+	private OzgCloudVorgangMapper mapper;
+
+	@Nested
+	class TestGetById {
+		@Captor
+		private ArgumentCaptor<GrpcFindVorgangWithEingangRequest> requestCaptor;
+
+		@BeforeEach
+		void init() {
+			when(stub.findVorgangWithEingang(any())).thenReturn(GrpcFindVorgangWithEingangResponseTestFactory.create());
+		}
+
+		@Test
+		void shouldCallStub() {
+			service.getById(OzgCloudVorgangTestFactory.ID);
+
+			verify(stub).findVorgangWithEingang(notNull());
+		}
+
+		@Test
+		void shouldHaveVorgangId() {
+			service.getById(OzgCloudVorgangTestFactory.ID);
+
+			verify(stub).findVorgangWithEingang(requestCaptor.capture());
+			assertThat(requestCaptor.getValue().getId()).isEqualTo(OzgCloudVorgangTestFactory.ID.toString());
+		}
+
+		@Test
+		void shouldMapResponse() {
+			service.getById(OzgCloudVorgangTestFactory.ID);
+
+			verify(mapper).fromGrpc(any());
+		}
+
+		@Test
+		void shouldReturnMappedVorgang() {
+			var vorgang = OzgCloudVorgangTestFactory.create();
+			when(mapper.fromGrpc(any())).thenReturn(vorgang);
+
+			var result = service.getById(OzgCloudVorgangTestFactory.ID);
+
+			assertThat(result).isSameAs(vorgang);
+		}
+	}
+
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangWithEingangTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangWithEingangTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..07233fa4c806343180b145167d749fe3653c73ab
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcVorgangWithEingangTestFactory.java
@@ -0,0 +1,27 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import static de.ozgcloud.apilib.vorgang.OzgCloudVorgangHeaderTestFactory.*;
+import static de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory.*;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcVorgangWithEingang;
+
+public class GrpcVorgangWithEingangTestFactory {
+
+	public static GrpcVorgangWithEingang create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcVorgangWithEingang.Builder createBuilder() {
+		return GrpcVorgangWithEingang.newBuilder()
+				.setId(ID.toString())
+				.setVersion(VERSION)
+				.setName(VORGANG_NAME)
+				.setNummer(VORGANG_NUMMER)
+				.setAktenzeichen(AKTENZEICHEN)
+				.setAssignedTo(ASSIGNED_TO.toString())
+				.setCreatedAt(CREATED_AT_STR)
+				.setStatus(STATUS.toString())
+				.setHeader(GrpcVorgangHeadTestFactory.create())
+				.setEingang(GrpcEingangTestFactory.create());
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcZustaendigeStelleTestFactory.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcZustaendigeStelleTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bc53e0ad7954c0124b100f9319942461c9ede83
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/GrpcZustaendigeStelleTestFactory.java
@@ -0,0 +1,19 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import static de.ozgcloud.apilib.vorgang.OzgCloudZustaendigeStelleTestFactory.*;
+
+import de.itvsh.ozg.pluto.vorgang.GrpcZustaendigeStelle;
+
+public class GrpcZustaendigeStelleTestFactory {
+
+	public static GrpcZustaendigeStelle create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcZustaendigeStelle.Builder createBuilder() {
+		return GrpcZustaendigeStelle.newBuilder()
+				.setOrganisationseinheitenId(ORGANISATIONS_EINHEIT_ID)
+				.setBezeichnung(BEZEICHNUNG)
+				.setEmail(EMAIL);
+	}
+}
diff --git a/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudVorgangMapperTest.java b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudVorgangMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..968338f9b69182ed2de918d9dd440d1e006d36a7
--- /dev/null
+++ b/api-lib-core/src/test/java/de/ozgcloud/apilib/vorgang/grpc/OzgCloudVorgangMapperTest.java
@@ -0,0 +1,52 @@
+package de.ozgcloud.apilib.vorgang.grpc;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+import org.mockito.InjectMocks;
+import org.mockito.Spy;
+
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangEingangTestFactory;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangHeaderTestFactory;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory;
+
+class OzgCloudVorgangMapperTest {
+
+	@InjectMocks
+	private OzgCloudVorgangMapper mapper = Mappers.getMapper(OzgCloudVorgangMapper.class);
+
+	@Spy
+	private OzgCloudEingangMapper eingangMapper = Mappers.getMapper(OzgCloudEingangMapper.class);
+
+	@Nested
+	class TestFromGrpc {
+		@Test
+		void shouldMapVorgangStub() {
+			var mapped = mapper.fromGrpc(GrpcVorgangWithEingangTestFactory.create());
+
+			assertThat(mapped).usingRecursiveComparison()
+					.ignoringFields("eingangs", "header")
+					.isEqualTo(OzgCloudVorgangTestFactory.create());
+		}
+
+		@Test
+		void shouldMapHeader() {
+			var mapped = mapper.fromGrpc(GrpcVorgangWithEingangTestFactory.create());
+
+			assertThat(mapped.getHeader()).usingRecursiveComparison()
+					.isEqualTo(OzgCloudVorgangHeaderTestFactory.create());
+		}
+
+		@Test
+		void shouldMapEingang() {
+			var mapped = mapper.fromGrpc(GrpcVorgangWithEingangTestFactory.create());
+
+			assertThat(mapped.getEingangs()).hasSize(1).first()
+					.usingRecursiveComparison()
+					.isEqualTo(OzgCloudVorgangEingangTestFactory.create());
+		}
+	}
+
+}
diff --git a/api-lib-core/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/api-lib-core/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension
new file mode 100644
index 0000000000000000000000000000000000000000..79b126e6cdb86bec1f4f08c205de8961bde1934a
--- /dev/null
+++ b/api-lib-core/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/api-lib-core/src/test/resources/junit-platform.properties b/api-lib-core/src/test/resources/junit-platform.properties
new file mode 100644
index 0000000000000000000000000000000000000000..1cebb76d5a58ac034b2627d12411d82d1e85821e
--- /dev/null
+++ b/api-lib-core/src/test/resources/junit-platform.properties
@@ -0,0 +1 @@
+junit.jupiter.extensions.autodetection.enabled = true
\ No newline at end of file