diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
index 45d0b05c577a8851b7c938e2c7de45edc36cc89b..5e46e02e16003da416af66fefef52c5e2900f819 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
@@ -70,6 +70,7 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto
                 environmentCdnurlSubmission.text = "Submission CDN:\n${state.urlSubmission}"
                 environmentCdnurlVerification.text = "Verification CDN:\n${state.urlVerification}"
                 environmentUrlDatadonation.text = "DataDonation:\n${state.urlDataDonation}"
+                environmentUrlTracelocation.text = "Create TraceLocation:\n${state.urlCreateTraceLocation}"
             }
         }
         vm.environmentChangeEvent.observe2(this) {
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
index fb3a8ded80765be7fe43f2487775ff3bfcfa9b2a..de39d889a768a6ff4c5f6b447b33f76b831381e2 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
@@ -8,7 +8,8 @@ data class EnvironmentState(
     val urlSubmission: String,
     val urlDownload: String,
     val urlVerification: String,
-    val urlDataDonation: String
+    val urlDataDonation: String,
+    val urlCreateTraceLocation: String
 ) {
     companion object {
         internal fun EnvironmentSetup.toEnvironmentState() = EnvironmentState(
@@ -17,7 +18,8 @@ data class EnvironmentState(
             urlSubmission = submissionCdnUrl,
             urlDownload = downloadCdnUrl,
             urlVerification = verificationCdnUrl,
-            urlDataDonation = dataDonationCdnUrl
+            urlDataDonation = dataDonationCdnUrl,
+            urlCreateTraceLocation = traceLocationCdnUrl
         )
     }
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestFragment.kt
index 3e6daef237373951dc50bf59d214b44f3b72232b..87006f2a43461eda2fe0ab2110fa4c7f0b465a0b 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestFragment.kt
@@ -49,16 +49,25 @@ class CreateEventTestFragment : Fragment(R.layout.fragment_test_createevent), Au
 
     private fun initOnCreateEventClicked() = with(binding) {
         createEventButton.setOnClickListener {
-            vm.createEvent(
-                eventOrLocationSpinner.editText!!.text.toString(),
-                eventDescription.text.toString(),
-                eventAddress.text.toString(),
-                eventStartEditText.text.toString(),
-                eventEndEditText.text.toString(),
-                eventDefaultCheckinLengthInMinutes.text.toString()
-            )
+            createEvent()
             it.hideKeyboard()
         }
+        sendToServerButton.setOnClickListener {
+            createEvent(sendToServer = true)
+            it.hideKeyboard()
+        }
+    }
+
+    private fun FragmentTestCreateeventBinding.createEvent(sendToServer: Boolean = false) {
+        vm.createEvent(
+            eventOrLocationSpinner.editText!!.text.toString(),
+            eventDescription.text.toString(),
+            eventAddress.text.toString(),
+            eventStartEditText.text.toString(),
+            eventEndEditText.text.toString(),
+            eventDefaultCheckinLengthInMinutes.text.toString(),
+            sendToServer
+        )
     }
 
     private fun initSpinner() {
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestViewModel.kt
index 264bb97c7c25f274b7e3ab1a6cb46668d04035f0..9ba5907a542d5ad910541c9cca9dfe193cb34a38 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/createevent/CreateEventTestViewModel.kt
@@ -4,9 +4,11 @@ import androidx.lifecycle.MutableLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
+import de.rki.coronawarnapp.eventregistration.events.TraceLocationCreator
+import de.rki.coronawarnapp.eventregistration.events.TraceLocationUserInput
 import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
-import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
-import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
@@ -18,6 +20,7 @@ import java.util.UUID
 
 class CreateEventTestViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
+    private val traceLocationCreator: TraceLocationCreator,
     private val traceLocationRepository: TraceLocationRepository
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
@@ -32,7 +35,8 @@ class CreateEventTestViewModel @AssistedInject constructor(
         address: String,
         start: String,
         end: String,
-        defaultCheckInLengthInMinutes: String
+        defaultCheckInLengthInMinutes: String,
+        sendToServer: Boolean = false
     ) {
         try {
             val startDate =
@@ -40,31 +44,43 @@ class CreateEventTestViewModel @AssistedInject constructor(
             val endDate =
                 if (end.isBlank()) null else DateTime.parse(end, DateTimeFormat.forPattern("yyyy-MM-dd HH:mm"))
 
-            /* TODO: wait for new protobuf messages 'TraceLocation' and perform network request to get
-                'SignedTraceLocation' */
-
-            // Backend needs UNIX timestamp in Seconds, not milliseconds
-            val startTimeStampSeconds = startDate?.toInstant()?.seconds ?: 0
-            val endTimeStampSeconds = endDate?.toInstant()?.seconds ?: 0
-
             val traceLocationType =
-                if (type == "Event") TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER
-                else TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER
+                if (type == "Event") LOCATION_TYPE_TEMPORARY_OTHER else LOCATION_TYPE_PERMANENT_OTHER
 
-            val traceLocation = TraceLocation(
-                UUID.randomUUID().toString(), // will be provided by the server when the endpoint is ready
-                traceLocationType,
-                description,
-                address,
-                startDate?.toInstant(),
-                endDate?.toInstant(),
-                defaultCheckInLengthInMinutes.toInt(),
-                "ByteRepresentation".toByteArray().toByteString(),
-                "ServerSignature".toByteArray().toByteString()
-            )
+            if (sendToServer) {
+                val userInput = TraceLocationUserInput(
+                    traceLocationType,
+                    description,
+                    address,
+                    startDate?.toInstant(),
+                    endDate?.toInstant(),
+                    defaultCheckInLengthInMinutes.toInt()
+                )
 
-            traceLocationRepository.addTraceLocation(traceLocation)
-            result.postValue(Result.Success(traceLocation))
+                launch {
+                    try {
+                        val traceLocation = traceLocationCreator.createTraceLocation(userInput)
+                        result.postValue(Result.Success(traceLocation))
+                    } catch (exception: Exception) {
+                        Timber.d("Something went wrong when sending the event to the server $exception")
+                        result.postValue(Result.Error)
+                    }
+                }
+            } else {
+                val traceLocation = TraceLocation(
+                    UUID.randomUUID().toString(),
+                    traceLocationType,
+                    description,
+                    address,
+                    startDate?.toInstant(),
+                    endDate?.toInstant(),
+                    defaultCheckInLengthInMinutes.toInt(),
+                    "ByteRepresentation".toByteArray().toByteString(),
+                    "ServerSignature".toByteArray().toByteString()
+                )
+                traceLocationRepository.addTraceLocation(traceLocation)
+                result.postValue(Result.Success(traceLocation))
+            }
         } catch (exception: Exception) {
             Timber.d("Something went wrong when trying to create an event: $exception")
             result.postValue(Result.Error)
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_createevent.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_createevent.xml
index afd82d5c5bb5f5f2b149d587eae2549a9a3204ac..1b654e9f6dc04d4f8ab6fa85b70b8a9513c184e2 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_createevent.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_createevent.xml
@@ -54,6 +54,7 @@
                     android:hint="Description"
                     android:maxLines="1"
                     android:padding="@dimen/spacing_tiny"
+                    android:text="TraceLocation created from TestMenu"
                     tools:ignore="HardcodedText" />
 
             </com.google.android.material.textfield.TextInputLayout>
@@ -71,6 +72,7 @@
                     android:hint="Address"
                     android:maxLines="1"
                     android:padding="@dimen/spacing_tiny"
+                    android:text="Address of TraceLocation"
                     tools:ignore="HardcodedText" />
 
             </com.google.android.material.textfield.TextInputLayout>
@@ -89,6 +91,7 @@
                     android:hint="Start (yyyy-MM-dd HH:mm)"
                     android:maxLines="1"
                     android:padding="@dimen/spacing_tiny"
+                    android:text="2020-01-15 15:00"
                     tools:ignore="HardcodedText" />
 
             </com.google.android.material.textfield.TextInputLayout>
@@ -107,6 +110,7 @@
                     android:hint="End (yyyy-MM-dd HH:mm)"
                     android:maxLines="1"
                     android:padding="@dimen/spacing_tiny"
+                    android:text="2020-01-15 18:00"
                     tools:ignore="HardcodedText" />
 
             </com.google.android.material.textfield.TextInputLayout>
@@ -126,6 +130,7 @@
                     android:maxLines="1"
                     android:padding="@dimen/spacing_tiny"
                     android:inputType="numberDecimal"
+                    android:text="90"
                     tools:ignore="HardcodedText" />
 
             </com.google.android.material.textfield.TextInputLayout>
@@ -137,6 +142,14 @@
                 android:text="Create Event"
                 tools:ignore="HardcodedText" />
 
+            <com.google.android.material.button.MaterialButton
+                android:id="@+id/send_to_server_button"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="8dp"
+                android:text="Send to server"
+                tools:ignore="HardcodedText" />
+
             <TextView
                 android:id="@+id/resultText"
                 style="@style/subtitle"
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
index cedba81d312970d03e1c16c12dbdb69b669439e3..66b4c97cc1236425f16b107e5894631b480aa32b 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
@@ -18,9 +18,9 @@
             <androidx.constraintlayout.widget.ConstraintLayout
                 android:id="@+id/debug_container"
                 style="@style/Card"
-                android:layout_margin="@dimen/spacing_tiny"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content">
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/spacing_tiny">
 
                 <TextView
                     android:id="@+id/debug_container_title"
@@ -115,6 +115,17 @@
                     app:layout_constraintTop_toBottomOf="@+id/environment_cdnurl_verification"
                     tools:text="DataDonation: ?" />
 
+                <TextView
+                    android:id="@+id/environment_url_tracelocation"
+                    style="@style/body2"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/spacing_tiny"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toBottomOf="@+id/environment_url_datadonation"
+                    tools:text="Create TraceLocation: ?" />
+
                 <RadioGroup
                     android:id="@+id/environment_toggle_group"
                     android:layout_width="match_parent"
@@ -124,7 +135,7 @@
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/environment_url_datadonation" />
+                    app:layout_constraintTop_toBottomOf="@+id/environment_url_tracelocation" />
             </androidx.constraintlayout.widget.ConstraintLayout>
 
         </LinearLayout>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt
index 1476022658f27fc6711345379d875e055c8098d3..8249835b1dec34abb7ae92f90ba614f4ce3674ff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt
@@ -5,6 +5,7 @@ import androidx.core.content.edit
 import com.google.gson.Gson
 import com.google.gson.JsonObject
 import com.google.gson.JsonPrimitive
+import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.CREATE_TRACELOCATION
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DATA_DONATION
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DOWNLOAD
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.LOG_UPLOAD
@@ -34,6 +35,7 @@ class EnvironmentSetup @Inject constructor(
         DOWNLOAD("DOWNLOAD_CDN_URL"),
         VERIFICATION_KEYS("PUB_KEYS_SIGNATURE_VERIFICATION"),
         DATA_DONATION("DATA_DONATION_CDN_URL"),
+        CREATE_TRACELOCATION("CREATE_TRACELOCATION_URL"),
         LOG_UPLOAD("LOG_UPLOAD_SERVER_URL"),
         SAFETYNET_API_KEY("SAFETYNET_API_KEY")
     }
@@ -115,6 +117,8 @@ class EnvironmentSetup @Inject constructor(
         get() = getEnvironmentValue(DOWNLOAD).asString
     val dataDonationCdnUrl: String
         get() = getEnvironmentValue(DATA_DONATION).asString
+    val traceLocationCdnUrl: String
+        get() = getEnvironmentValue(CREATE_TRACELOCATION).asString
 
     val appConfigVerificationKey: String
         get() = getEnvironmentValue(VERIFICATION_KEYS).asString
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/CreateTraceLocationCDNServerUrl.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/CreateTraceLocationCDNServerUrl.kt
new file mode 100644
index 0000000000000000000000000000000000000000..69756ed82cd852fc7e3693960e00ab28f6923ca1
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/CreateTraceLocationCDNServerUrl.kt
@@ -0,0 +1,8 @@
+package de.rki.coronawarnapp.environment.eventregistration
+
+import javax.inject.Qualifier
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class CreateTraceLocationCDNServerUrl
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/CreateTraceLocationModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/CreateTraceLocationModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..814a89969c68c9d2348a303d425ab9c3cddbfc27
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/CreateTraceLocationModule.kt
@@ -0,0 +1,47 @@
+package de.rki.coronawarnapp.environment.eventregistration
+
+import dagger.Module
+import dagger.Provides
+import dagger.Reusable
+import de.rki.coronawarnapp.environment.BaseEnvironmentModule
+import de.rki.coronawarnapp.environment.EnvironmentSetup
+import de.rki.coronawarnapp.eventregistration.events.server.CreateTraceLocationApiV1
+import de.rki.coronawarnapp.http.HttpClientDefault
+import okhttp3.OkHttpClient
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.protobuf.ProtoConverterFactory
+import javax.inject.Singleton
+
+@Module
+class CreateTraceLocationModule : BaseEnvironmentModule() {
+
+    @Reusable
+    @TraceLocationCDNHttpClient
+    @Provides
+    fun cdnHttpClient(@HttpClientDefault okHttpClient: OkHttpClient): OkHttpClient = okHttpClient.newBuilder().build()
+
+    @Singleton
+    @CreateTraceLocationCDNServerUrl
+    @Provides
+    fun provideCreateTraceLocationCDNServerUrl(environment: EnvironmentSetup): String {
+        val url = environment.traceLocationCdnUrl
+        return requireValidUrl(url)
+    }
+
+    @Singleton
+    @Provides
+    fun provideCreateTraceLocationApi(
+        @TraceLocationCDNHttpClient okHttpClient: OkHttpClient,
+        @CreateTraceLocationCDNServerUrl url: String,
+        protoConverterFactory: ProtoConverterFactory,
+        gsonConverterFactory: GsonConverterFactory
+    ): CreateTraceLocationApiV1 =
+        Retrofit.Builder()
+            .client(okHttpClient)
+            .baseUrl(url)
+            .addConverterFactory(protoConverterFactory)
+            .addConverterFactory(gsonConverterFactory)
+            .build()
+            .create(CreateTraceLocationApiV1::class.java)
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/TraceLocationCDNHttpClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/TraceLocationCDNHttpClient.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a424b7659c2a3f3ad7f975c81d50967a6b70850b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/eventregistration/TraceLocationCDNHttpClient.kt
@@ -0,0 +1,8 @@
+package de.rki.coronawarnapp.environment.eventregistration
+
+import javax.inject.Qualifier
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class TraceLocationCDNHttpClient
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt
index 225c6afeae5ea5c9307518071e7287b666654753..090a9c4d1cf60a7b8d07842461e5af8b1c7844ca 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/EventRegistrationModule.kt
@@ -2,13 +2,19 @@ package de.rki.coronawarnapp.eventregistration
 
 import dagger.Binds
 import dagger.Module
+import de.rki.coronawarnapp.environment.eventregistration.CreateTraceLocationModule
 import de.rki.coronawarnapp.eventregistration.checkins.download.DownloadedCheckInsRepo
 import de.rki.coronawarnapp.eventregistration.checkins.download.FakeDownloadedCheckInsRepo
 import de.rki.coronawarnapp.eventregistration.storage.repo.DefaultTraceLocationRepository
 import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
 
-@Module
+@Module(
+    includes = [
+        CreateTraceLocationModule::class
+    ]
+)
 abstract class EventRegistrationModule {
+
     @Binds
     abstract fun traceLocationRepository(defaultTraceLocationRepo: DefaultTraceLocationRepository):
         TraceLocationRepository
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt
index d7d49bd547cc59434414797e9a17a514f5c6e193..c55e49759a20fbcf7a8e0bf904ac93317f482c6d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt
@@ -3,9 +3,11 @@ package de.rki.coronawarnapp.eventregistration.checkins.qrcode
 import android.os.Parcelable
 import de.rki.coronawarnapp.eventregistration.storage.entity.TraceLocationEntity
 import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocation.parseFrom
 import kotlinx.parcelize.Parcelize
 import okio.ByteString
 import okio.ByteString.Companion.decodeBase64
+import okio.ByteString.Companion.toByteString
 import org.joda.time.Instant
 
 const val TRACE_LOCATION_VERSION = 1
@@ -43,3 +45,23 @@ fun TraceLocationEntity.toTraceLocation() = TraceLocation(
     signature = signatureBase64.decodeBase64()!!,
     version = version
 )
+
+fun TraceLocationOuterClass.SignedTraceLocation.toTraceLocation(): TraceLocation {
+
+    val traceLocation = parseFrom(location)
+
+    fun Long.getInstantOrNull() = if (this == 0L) null else Instant.ofEpochSecond(this)
+
+    return TraceLocation(
+        guid = traceLocation.guid,
+        type = traceLocation.type,
+        description = traceLocation.description,
+        address = traceLocation.address,
+        startDate = traceLocation.startTimestamp.getInstantOrNull(),
+        endDate = traceLocation.endTimestamp.getInstantOrNull(),
+        defaultCheckInLengthInMinutes = traceLocation.defaultCheckInLengthInMinutes,
+        byteRepresentation = traceLocation.toByteArray().toByteString(),
+        signature = signature.toByteArray().toByteString(),
+        version = traceLocation.version
+    )
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationCreator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationCreator.kt
new file mode 100644
index 0000000000000000000000000000000000000000..925fc8e7cf2e409ee38e1d8dffbe7e4502943014
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationCreator.kt
@@ -0,0 +1,51 @@
+package de.rki.coronawarnapp.eventregistration.events
+
+import dagger.Lazy
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.toTraceLocation
+import de.rki.coronawarnapp.eventregistration.events.server.TraceLocationServer
+import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
+import de.rki.coronawarnapp.util.security.SignatureValidation
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+
+const val TRACE_LOCATION_VERSION = 1
+
+@Singleton
+class TraceLocationCreator @Inject constructor(
+    private val api: Lazy<TraceLocationServer>,
+    private val repository: TraceLocationRepository,
+    private val signatureValidation: SignatureValidation
+) {
+
+    suspend fun createTraceLocation(traceLocationUserInput: TraceLocationUserInput): TraceLocation {
+
+        val signedTraceLocation = api.get().retrieveSignedTraceLocation(traceLocationUserInput)
+
+        val isSignatureValid = try {
+            signatureValidation.hasValidSignature(
+                signedTraceLocation.location.toByteArray(),
+                sequenceOf(signedTraceLocation.signature.toByteArray())
+            )
+        } catch (exception: Exception) {
+            Timber.e("Signature Validation Failed: $exception")
+            throw SignatureValidationFailedException("Signature Validation failed", exception)
+        }
+
+        if (!isSignatureValid) {
+            Timber.e("The received trace location has an invalid signature")
+            throw InvalidSignatureException("The received trace location has an invalid signature", null)
+        }
+
+        val traceLocation = signedTraceLocation.toTraceLocation()
+
+        repository.addTraceLocation(traceLocation)
+
+        return traceLocation
+    }
+}
+
+// TODO: Finalize Error Handling in a future PR when it was specified in TechSpecs
+class InvalidSignatureException(message: String?, cause: Throwable?) : Exception(message, cause)
+class SignatureValidationFailedException(message: String?, cause: Throwable?) : Exception(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationUserInput.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationUserInput.kt
new file mode 100644
index 0000000000000000000000000000000000000000..139fe361c96a6c1c3aaaafbc6128c2026dc5a09e
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationUserInput.kt
@@ -0,0 +1,13 @@
+package de.rki.coronawarnapp.eventregistration.events
+
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import org.joda.time.Instant
+
+data class TraceLocationUserInput(
+    val type: TraceLocationOuterClass.TraceLocationType,
+    val description: String,
+    val address: String,
+    val startDate: Instant?,
+    val endDate: Instant?,
+    val defaultCheckInLengthInMinutes: Int
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/server/CreateTraceLocationApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/server/CreateTraceLocationApiV1.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c8a56a67f855eaaecdbd7bd2ab5100af0fb8cb64
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/server/CreateTraceLocationApiV1.kt
@@ -0,0 +1,14 @@
+package de.rki.coronawarnapp.eventregistration.events.server
+
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import retrofit2.Response
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+interface CreateTraceLocationApiV1 {
+
+    @POST("/version/v1/trace-location")
+    suspend fun createTraceLocation(
+        @Body requestBody: TraceLocationOuterClass.TraceLocation
+    ): Response<TraceLocationOuterClass.SignedTraceLocation>
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationServer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1c6b3e0936e20e28554eb1935026f30a17ac8701
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationServer.kt
@@ -0,0 +1,49 @@
+package de.rki.coronawarnapp.eventregistration.events.server
+
+import androidx.annotation.VisibleForTesting
+import dagger.Lazy
+import de.rki.coronawarnapp.eventregistration.events.TRACE_LOCATION_VERSION
+import de.rki.coronawarnapp.eventregistration.events.TraceLocationUserInput
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import retrofit2.HttpException
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class TraceLocationServer @Inject constructor(
+    private val api: Lazy<CreateTraceLocationApiV1>
+) {
+
+    suspend fun retrieveSignedTraceLocation(
+        traceLocationUserInput: TraceLocationUserInput
+    ): TraceLocationOuterClass.SignedTraceLocation {
+
+        val traceLocationProto = traceLocationUserInput.toTraceLocationProtoBuf()
+        val response = api.get().createTraceLocation(traceLocationProto)
+
+        if (!response.isSuccessful) throw HttpException(response)
+        if (response.body() == null) {
+            throw IllegalStateException("Response is successful, but body is empty.")
+        }
+
+        val signedTraceLocation = response.body()!!
+
+        Timber.d("Successfully received %s", signedTraceLocation)
+        return signedTraceLocation
+    }
+}
+
+@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+fun TraceLocationUserInput.toTraceLocationProtoBuf(): TraceLocationOuterClass.TraceLocation {
+    return TraceLocationOuterClass.TraceLocation.newBuilder()
+        .setVersion(TRACE_LOCATION_VERSION)
+        .setType(type)
+        .setDescription(description)
+        .setAddress(address)
+        .setStartTimestamp(startDate?.seconds ?: 0)
+        .setEndTimestamp(endDate?.seconds ?: 0)
+        .setDefaultCheckInLengthInMinutes(defaultCheckInLengthInMinutes)
+        .build()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/DefaultTraceLocationRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/DefaultTraceLocationRepository.kt
index 42e9b689de70d02c062d7ca00013023336ace753..31a061fd5e201df0e6fd4f44de53bb3a4469fc3f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/DefaultTraceLocationRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/DefaultTraceLocationRepository.kt
@@ -31,18 +31,18 @@ class DefaultTraceLocationRepository @Inject constructor(
     override val allTraceLocations: Flow<List<TraceLocation>>
         get() = traceLocationDao.allEntries().map { it.toTraceLocations() }
 
-    override fun addTraceLocation(event: TraceLocation) {
+    override fun addTraceLocation(traceLocation: TraceLocation) {
         appScope.launch {
-            Timber.d("Add hosted event: $event")
-            val eventEntity = event.toTraceLocationEntity()
+            Timber.d("Add hosted event: $traceLocation")
+            val eventEntity = traceLocation.toTraceLocationEntity()
             traceLocationDao.insert(eventEntity)
         }
     }
 
-    override fun deleteTraceLocation(event: TraceLocation) {
+    override fun deleteTraceLocation(traceLocation: TraceLocation) {
         appScope.launch {
-            Timber.d("Delete hosted event: $event")
-            val eventEntity = event.toTraceLocationEntity()
+            Timber.d("Delete hosted event: $traceLocation")
+            val eventEntity = traceLocation.toTraceLocationEntity()
             traceLocationDao.delete(eventEntity)
         }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/TraceLocationRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/TraceLocationRepository.kt
index 17ab6fff55381a602b6809f809f15033e05bd72a..fe94d86be1bdf396a4b6ce1f2cf2c84f41151c96 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/TraceLocationRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/storage/repo/TraceLocationRepository.kt
@@ -7,9 +7,9 @@ interface TraceLocationRepository {
 
     val allTraceLocations: Flow<List<TraceLocation>>
 
-    fun addTraceLocation(event: TraceLocation)
+    fun addTraceLocation(traceLocation: TraceLocation)
 
-    fun deleteTraceLocation(event: TraceLocation)
+    fun deleteTraceLocation(traceLocation: TraceLocation)
 
     fun deleteAllTraceLocations()
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt
index 62534f7290aa26c8cc7948ecfc0b71cd7b3166f1..bdde7bc4b2042dd63f9e3f034599452f0cf4422c 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt
@@ -67,6 +67,7 @@ class EnvironmentSetupTest : BaseTest() {
                 safetyNetApiKey shouldBe "placeholder-${env.rawKey}"
                 dataDonationCdnUrl shouldBe "https://datadonation-${env.rawKey}"
                 logUploadServerUrl shouldBe "https://logupload-${env.rawKey}"
+                traceLocationCdnUrl shouldBe "https://tracelocation-${env.rawKey}"
             }
         }
     }
@@ -124,7 +125,8 @@ class EnvironmentSetupTest : BaseTest() {
         EnvironmentSetup.EnvKey.DATA_DONATION.rawKey shouldBe "DATA_DONATION_CDN_URL"
         EnvironmentSetup.EnvKey.LOG_UPLOAD.rawKey shouldBe "LOG_UPLOAD_SERVER_URL"
         EnvironmentSetup.EnvKey.SAFETYNET_API_KEY.rawKey shouldBe "SAFETYNET_API_KEY"
-        EnvironmentSetup.EnvKey.values().size shouldBe 8
+        EnvironmentSetup.EnvKey.CREATE_TRACELOCATION.rawKey shouldBe "CREATE_TRACELOCATION_URL"
+        EnvironmentSetup.EnvKey.values().size shouldBe 9
     }
 
     companion object {
@@ -145,6 +147,7 @@ class EnvironmentSetupTest : BaseTest() {
                     "VERIFICATION_CDN_URL": "https://verification-PROD",
                     "DATA_DONATION_CDN_URL": "https://datadonation-PROD",
                     "LOG_UPLOAD_SERVER_URL": "https://logupload-PROD",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-PROD",
                     "SAFETYNET_API_KEY": "placeholder-PROD",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-PROD"
                 },
@@ -155,9 +158,10 @@ class EnvironmentSetupTest : BaseTest() {
                     "VERIFICATION_CDN_URL": "https://verification-DEV",
                     "DATA_DONATION_CDN_URL": "https://datadonation-DEV",
                     "LOG_UPLOAD_SERVER_URL": "https://logupload-DEV",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-DEV",
                     "SAFETYNET_API_KEY": "placeholder-DEV",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-DEV"
-                },
+               },
                 "INT": {
                     "USE_EUR_KEY_PKGS" : false,
                     "SUBMISSION_CDN_URL": "https://submission-INT",
@@ -165,6 +169,7 @@ class EnvironmentSetupTest : BaseTest() {
                     "VERIFICATION_CDN_URL": "https://verification-INT",
                     "DATA_DONATION_CDN_URL": "https://datadonation-INT",
                     "LOG_UPLOAD_SERVER_URL": "https://logupload-INT",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-INT",
                     "SAFETYNET_API_KEY": "placeholder-INT",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-INT"
                 },
@@ -175,8 +180,10 @@ class EnvironmentSetupTest : BaseTest() {
                     "VERIFICATION_CDN_URL": "https://verification-WRU",
                     "DATA_DONATION_CDN_URL": "https://datadonation-WRU",
                     "LOG_UPLOAD_SERVER_URL": "https://logupload-WRU",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-WRU",
                     "SAFETYNET_API_KEY": "placeholder-WRU",
-                    "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU"
+                    "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-WRU"
                 },
                 "WRU-XD": {
                     "USE_EUR_KEY_PKGS" : true,
@@ -185,6 +192,7 @@ class EnvironmentSetupTest : BaseTest() {
                     "VERIFICATION_CDN_URL": "https://verification-WRU-XD",
                     "DATA_DONATION_CDN_URL": "https://datadonation-WRU-XD",
                     "LOG_UPLOAD_SERVER_URL": "https://logupload-WRU-XD",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-WRU-XD",
                     "SAFETYNET_API_KEY": "placeholder-WRU-XD",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XD"
                 },
@@ -195,6 +203,7 @@ class EnvironmentSetupTest : BaseTest() {
                     "VERIFICATION_CDN_URL": "https://verification-WRU-XA",
                     "DATA_DONATION_CDN_URL": "https://datadonation-WRU-XA",
                     "LOG_UPLOAD_SERVER_URL": "https://logupload-WRU-XA",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-WRU-XA",
                     "SAFETYNET_API_KEY": "placeholder-WRU-XA",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XA"
                 },
@@ -205,6 +214,7 @@ class EnvironmentSetupTest : BaseTest() {
                     "VERIFICATION_CDN_URL": "https://verification-LOCAL",
                     "DATA_DONATION_CDN_URL": "https://datadonation-LOCAL",
                     "LOG_UPLOAD_SERVER_URL": "https://logupload-LOCAL",
+                    "CREATE_TRACELOCATION_URL": "https://tracelocation-LOCAL",
                     "SAFETYNET_API_KEY": "placeholder-LOCAL",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-LOCAL"
                 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/SignedTraceLocationToTraceLocationMapperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/SignedTraceLocationToTraceLocationMapperTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..73e845e338116bb5e8bdca0b3322c80b2fb39bc8
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/SignedTraceLocationToTraceLocationMapperTest.kt
@@ -0,0 +1,44 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+import de.rki.coronawarnapp.eventregistration.events.server.TraceLocationData
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.toByteString
+import org.joda.time.Instant
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+internal class SignedTraceLocationToTraceLocationMapperTest : BaseTest() {
+
+    @Test
+    fun `SignedTraceLocation_toTraceLocation() should map temporary event correctly`() {
+        TraceLocationData.signedTraceLocationTemporary.toTraceLocation() shouldBe TraceLocation(
+            guid = "serverGeneratedGuid",
+            version = 1,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+            description = "Event Registration Release Party",
+            address = "SAP Headquarter",
+            startDate = Instant.parse("2021-05-01T19:00:00.000Z"),
+            endDate = Instant.parse("2021-05-01T23:30:00.000Z"),
+            byteRepresentation = TraceLocationData.signedTraceLocationTemporary.location.toByteArray().toByteString(),
+            signature = "ServerSignature".toByteArray().toByteString(),
+            defaultCheckInLengthInMinutes = 180
+        )
+    }
+
+    @Test
+    fun `SignedTraceLocation_toTraceLocation() should map permanent event correctly`() {
+        TraceLocationData.signedTraceLocationPermanent.toTraceLocation() shouldBe TraceLocation(
+            guid = "serverGeneratedGuid",
+            version = 1,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER,
+            description = "IceCream Shop",
+            address = "IceCream Wonderland Street 1",
+            startDate = null,
+            endDate = null,
+            byteRepresentation = TraceLocationData.signedTraceLocationPermanent.location.toByteArray().toByteString(),
+            signature = "ServerSignature".toByteArray().toByteString(),
+            defaultCheckInLengthInMinutes = 30
+        )
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationCreatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationCreatorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cb260f3ddb23040e4af5b53632f883ebd1749ba8
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationCreatorTest.kt
@@ -0,0 +1,79 @@
+package de.rki.coronawarnapp.eventregistration.events
+
+import com.google.protobuf.ByteString
+import dagger.Lazy
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.toTraceLocation
+import de.rki.coronawarnapp.eventregistration.events.server.TraceLocationServer
+import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import de.rki.coronawarnapp.util.security.SignatureValidation
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import io.mockk.verify
+import kotlinx.coroutines.test.runBlockingTest
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+internal class TraceLocationCreatorTest : BaseTest() {
+
+    @MockK lateinit var api: Lazy<TraceLocationServer>
+    @MockK lateinit var repository: TraceLocationRepository
+    @MockK lateinit var signatureValidation: SignatureValidation
+
+    @BeforeEach
+    fun setUp() {
+        MockKAnnotations.init(this)
+    }
+
+    private fun createInstance() = TraceLocationCreator(api, repository, signatureValidation)
+
+    @Test
+    fun `createTraceLocation() should return traceLocation and store it in repository when everything works fine`() =
+        runBlockingTest {
+
+            val traceLocationToReturn = TraceLocationOuterClass.TraceLocation.newBuilder()
+                .setVersion(TRACE_LOCATION_VERSION)
+                .setType(TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT)
+                .setDescription("Top Secret Private Event")
+                .setAddress("top secret address")
+                .setStartTimestamp(Instant.parse("2020-01-01T14:00:00.000Z").seconds)
+                .setEndTimestamp(Instant.parse("2020-01-01T18:00:00.000Z").seconds)
+                .setDefaultCheckInLengthInMinutes(180)
+                .build()
+
+            val signedTraceLocationToReturn = TraceLocationOuterClass.SignedTraceLocation.newBuilder()
+                .setLocation(traceLocationToReturn.toByteString())
+                .setSignature(ByteString.copyFromUtf8("Signature"))
+                .build()
+
+            coEvery { api.get().retrieveSignedTraceLocation(any()) } returns signedTraceLocationToReturn
+            every { signatureValidation.hasValidSignature(any(), any()) } returns true
+            every { repository.addTraceLocation(any()) } just Runs
+
+            val userInput = TraceLocationUserInput(
+                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT,
+                description = "Top Secret Private Event",
+                address = "top secret address",
+                startDate = Instant.parse("2020-01-01T14:00:00.000Z"),
+                endDate = Instant.parse("2020-01-01T18:00:00.000Z"),
+                defaultCheckInLengthInMinutes = 180
+            )
+
+            val actualTraceLocation = createInstance().createTraceLocation(userInput)
+            val expectedTraceLocation = signedTraceLocationToReturn.toTraceLocation()
+
+            verify(exactly = 1) { repository.addTraceLocation(expectedTraceLocation) }
+
+            actualTraceLocation shouldBe expectedTraceLocation
+        }
+
+    // TODO: Add tests for exception handling when exception handling is specified in the TechSpecs
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/DefaultTraceLocationKtTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationMapperTest.kt
similarity index 99%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/DefaultTraceLocationKtTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationMapperTest.kt
index 88032335e06c03d8d6ccbdc8606b8da673f46b68..5e171b843c2f03417585fee74b56973d1ae14178 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/DefaultTraceLocationKtTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationMapperTest.kt
@@ -12,7 +12,7 @@ import org.joda.time.Instant
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
-internal class DefaultTraceLocationKtTest : BaseTest() {
+internal class TraceLocationMapperTest : BaseTest() {
 
     @Test
     fun `toTraceLocation() should map to correct object when providing all arguments`() {
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..797c31c55b5126afeb87a0f68ef52d263179c7e4
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationData.kt
@@ -0,0 +1,53 @@
+package de.rki.coronawarnapp.eventregistration.events.server
+
+import com.google.protobuf.ByteString
+import de.rki.coronawarnapp.eventregistration.events.TraceLocationUserInput
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import org.joda.time.Instant
+
+object TraceLocationData {
+
+    val traceLocationTemporaryUserInput = TraceLocationUserInput(
+        type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+        description = "Event Registration Release Party",
+        address = "SAP Headquarter",
+        startDate = Instant.parse("2021-05-01T19:00:00.000Z"),
+        endDate = Instant.parse("2021-05-01T23:30:00.000Z"),
+        defaultCheckInLengthInMinutes = 180
+    )
+
+    private val traceLocationTemporary: TraceLocationOuterClass.TraceLocation =
+        TraceLocationOuterClass.TraceLocation.newBuilder()
+            .setGuid("serverGeneratedGuid")
+            .setVersion(1)
+            .setType(TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER)
+            .setDescription("Event Registration Release Party")
+            .setAddress("SAP Headquarter")
+            .setStartTimestamp(Instant.parse("2021-05-01T19:00:00.000Z").seconds)
+            .setEndTimestamp(Instant.parse("2021-05-01T23:30:00.000Z").seconds)
+            .setDefaultCheckInLengthInMinutes(180)
+            .build()
+
+    val signedTraceLocationTemporary: TraceLocationOuterClass.SignedTraceLocation =
+        TraceLocationOuterClass.SignedTraceLocation.newBuilder()
+            .setLocation(traceLocationTemporary.toByteString())
+            .setSignature(ByteString.copyFromUtf8("ServerSignature"))
+            .build()
+
+    private val traceLocationPermanent: TraceLocationOuterClass.TraceLocation =
+        TraceLocationOuterClass.TraceLocation.newBuilder()
+            .setGuid("serverGeneratedGuid")
+            .setVersion(1)
+            .setType(TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER)
+            .setDescription("IceCream Shop")
+            .setAddress("IceCream Wonderland Street 1")
+            .setDefaultCheckInLengthInMinutes(30)
+            .build()
+
+    val signedTraceLocationPermanent: TraceLocationOuterClass.SignedTraceLocation =
+        TraceLocationOuterClass.SignedTraceLocation.newBuilder()
+            .setLocation(traceLocationPermanent.toByteString())
+            .setSignature(ByteString.copyFromUtf8("ServerSignature"))
+            .build()
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationServerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..945ba8fc06aadb9616282ecfbc9e321575437d5b
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/server/TraceLocationServerTest.kt
@@ -0,0 +1,106 @@
+package de.rki.coronawarnapp.eventregistration.events.server
+
+import dagger.Lazy
+import de.rki.coronawarnapp.eventregistration.events.TraceLocationUserInput
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import io.kotest.assertions.throwables.shouldThrow
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.coEvery
+import io.mockk.impl.annotations.MockK
+import kotlinx.coroutines.test.runBlockingTest
+import okhttp3.ResponseBody.Companion.toResponseBody
+import org.joda.time.Instant
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import retrofit2.HttpException
+import retrofit2.Response
+import testhelpers.BaseTest
+
+internal class TraceLocationServerTest : BaseTest() {
+
+    @MockK lateinit var api: Lazy<CreateTraceLocationApiV1>
+
+    @BeforeEach
+    fun setUp() {
+        MockKAnnotations.init(this)
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    private fun getInstance() = TraceLocationServer(api)
+
+    @Test
+    fun `retrieveSignedTraceLocation() should return SignedTraceLocation when everything works fine`() =
+        runBlockingTest {
+
+            val signedTraceLocationMock = TraceLocationData.signedTraceLocationTemporary
+            coEvery { api.get().createTraceLocation(any()) } returns Response.success(200, signedTraceLocationMock)
+
+            val userInput = TraceLocationData.traceLocationTemporaryUserInput
+            val actualSignedTraceLocation = getInstance().retrieveSignedTraceLocation(userInput)
+
+            actualSignedTraceLocation shouldBe signedTraceLocationMock
+        }
+
+    @Test
+    fun `retrieveSignedTraceLocation() should throw HttpException when we receive an unsuccessful response`() =
+        runBlockingTest {
+            coEvery { api.get().createTraceLocation(any()) } returns Response.error(
+                400,
+                "Client Error".toResponseBody()
+            )
+
+            shouldThrow<HttpException> {
+                getInstance().retrieveSignedTraceLocation(TraceLocationData.traceLocationTemporaryUserInput)
+            }
+        }
+
+    // TODO: Add additional error handling tests once it is defined in TecSpec
+
+    @Test
+    fun `toTraceLocationProtoBuf() should map user input correctly for temporary trace locations`() {
+        TraceLocationUserInput(
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+            description = "Event Registration Release Party",
+            address = "SAP Headquarter",
+            startDate = Instant.parse("2021-05-01T19:00:00.000Z"),
+            endDate = Instant.parse("2021-05-01T23:30:00.000Z"),
+            defaultCheckInLengthInMinutes = 180
+        ).toTraceLocationProtoBuf().run {
+            guid shouldBe ""
+            version shouldBe 1
+            type shouldBe TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER
+            description shouldBe "Event Registration Release Party"
+            address shouldBe "SAP Headquarter"
+            startTimestamp shouldBe Instant.parse("2021-05-01T19:00:00.000Z").seconds
+            endTimestamp shouldBe Instant.parse("2021-05-01T23:30:00.000Z").seconds
+            defaultCheckInLengthInMinutes shouldBe 180
+        }
+    }
+
+    @Test
+    fun `toTraceLocationProtoBuf() should map user input correctly for permanent trace locations`() {
+        TraceLocationUserInput(
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER,
+            description = "IceCream Shop",
+            address = "IceCream Wonderland Street 1",
+            startDate = null,
+            endDate = null,
+            defaultCheckInLengthInMinutes = 30
+        ).toTraceLocationProtoBuf().run {
+            guid shouldBe ""
+            version shouldBe 1
+            type shouldBe TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER
+            description shouldBe "IceCream Shop"
+            address shouldBe "IceCream Wonderland Street 1"
+            startTimestamp shouldBe 0
+            endTimestamp shouldBe 0
+            defaultCheckInLengthInMinutes shouldBe 30
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
index 7666b705e092c26da33a45c1f5fe515fa268c3c7..4ffeb6e16ff3ded079df2dcbda081d0d1a992c6f 100644
--- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
+++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
@@ -38,6 +38,7 @@ class DebugOptionsFragmentViewModelTest : BaseTestInstrumentation() {
         every { environmentSetup.downloadCdnUrl } returns "downloadUrl"
         every { environmentSetup.verificationCdnUrl } returns "verificationUrl"
         every { environmentSetup.dataDonationCdnUrl } returns "dataDonationUrl"
+        every { environmentSetup.traceLocationCdnUrl } returns "createTraceLocationUrl"
 
         every { environmentSetup.currentEnvironment = any() } answers {
             currentEnvironment = arg(0)