diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt
index 2914a06a81f61e586bf6a1a2ef1b8e0a1c5bf88a..b7c535d6e3aff991e1e08a40d8a5560e19adb1ff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt
@@ -2,7 +2,6 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.checkins
 
 import de.rki.coronawarnapp.presencetracing.checkins.CheckIn
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.VerifiedTraceLocation
-import de.rki.coronawarnapp.util.ui.LazyString
 
 sealed class CheckInEvent {
 
@@ -12,8 +11,6 @@ sealed class CheckInEvent {
 
     data class ConfirmCheckIn(val verifiedTraceLocation: VerifiedTraceLocation) : CheckInEvent()
 
-    data class InvalidQrCode(val errorText: LazyString) : CheckInEvent()
-
     data class ConfirmCheckInWithoutHistory(val verifiedTraceLocation: VerifiedTraceLocation) : CheckInEvent()
 
     data class EditCheckIn(val checkInId: Long, val position: Int) : CheckInEvent()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt
index cb181fa24ae6d1ed5d384b4009ae8b64a601149f..435473778403981e83be238abe1825ed20e72138 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt
@@ -32,7 +32,6 @@ import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator
 import de.rki.coronawarnapp.util.lists.diffutil.update
 import de.rki.coronawarnapp.util.onScroll
 import de.rki.coronawarnapp.util.tryHumanReadableError
-import de.rki.coronawarnapp.util.ui.LazyString
 import de.rki.coronawarnapp.util.ui.doNavigate
 import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
@@ -98,8 +97,6 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
                 )
             }
 
-            is CheckInEvent.InvalidQrCode -> showInvalidQrCodeInformation(event.errorText)
-
             is CheckInEvent.ConfirmCheckInWithoutHistory -> doNavigate(
                 CheckInsFragmentDirections.actionCheckInsFragmentToConfirmCheckInFragmentCleanHistory(
                     verifiedTraceLocation = event.verifiedTraceLocation
@@ -134,15 +131,6 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
         }
     }
 
-    private fun showInvalidQrCodeInformation(lazyErrorText: LazyString) {
-        MaterialAlertDialogBuilder(requireContext()).apply {
-            val errorText = lazyErrorText.get(context)
-            setTitle(R.string.trace_location_attendee_invalid_qr_code_dialog_title)
-            setMessage(getString(R.string.trace_location_attendee_invalid_qr_code_dialog_message, errorText))
-            setPositiveButton(R.string.trace_location_attendee_invalid_qr_code_dialog_positive_button) { _, _ -> }
-        }.show()
-    }
-
     private fun updateViews(items: List<CheckInsItem>) {
         checkInsAdapter.update(items)
         binding.apply {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt
index 9f89c87ea3221601957124d4f6b740dd8565a084..49ff5d5c58b886f892112fdbc136c6aa3a3cb786 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt
@@ -20,8 +20,6 @@ import de.rki.coronawarnapp.util.coroutine.AppScope
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.flow.intervalFlow
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
-import de.rki.coronawarnapp.util.ui.toLazyString
-import de.rki.coronawarnapp.util.ui.toResolvingString
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
 import kotlinx.coroutines.CoroutineScope
@@ -85,7 +83,7 @@ class CheckInsViewModel @AssistedInject constructor(
     }
 
     fun onRemoveAllCheckIns() {
-        Timber.d("onRemovaAllCheckIns()")
+        Timber.d("onRemoveAllCheckIns()")
         events.postValue(CheckInEvent.ConfirmRemoveAll)
     }
 
@@ -142,23 +140,15 @@ class CheckInsViewModel @AssistedInject constructor(
     }
 
     private fun verifyUri(uri: String) = launch {
-        try {
-            Timber.i("uri: $uri")
-            val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri)
-            when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) {
-                is TraceLocationVerifier.VerificationResult.Valid -> events.postValue(
-                    if (cleanHistory)
-                        CheckInEvent.ConfirmCheckInWithoutHistory(verifyResult.verifiedTraceLocation)
-                    else
-                        CheckInEvent.ConfirmCheckIn(verifyResult.verifiedTraceLocation)
-                )
-                is TraceLocationVerifier.VerificationResult.Invalid ->
-                    events.postValue(CheckInEvent.InvalidQrCode(verifyResult.errorTextRes.toResolvingString()))
-            }
-        } catch (e: Exception) {
-            Timber.d(e, "TraceLocation verification failed")
-            val msg = e.message ?: "QR-Code was invalid"
-            events.postValue(CheckInEvent.InvalidQrCode(msg.toLazyString()))
+        Timber.i("uri: $uri")
+        val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri)
+        when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) {
+            is TraceLocationVerifier.VerificationResult.Valid -> events.postValue(
+                if (cleanHistory)
+                    CheckInEvent.ConfirmCheckInWithoutHistory(verifyResult.verifiedTraceLocation)
+                else
+                    CheckInEvent.ConfirmCheckIn(verifyResult.verifiedTraceLocation)
+            )
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt
index 47ddf2f674d5fc0ba24113a654e00d04e7677198..d1729d68ba80b14e6a4e88f43cabee7be92906cb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt
@@ -8,6 +8,7 @@ import android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT
 import androidx.fragment.app.Fragment
 import androidx.navigation.NavOptions
 import androidx.navigation.fragment.findNavController
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.transition.MaterialContainerTransform
 import com.google.zxing.BarcodeFormat
 import com.journeyapps.barcodescanner.DefaultDecoderFactory
@@ -17,6 +18,7 @@ import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.CheckInsFragmen
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.permission.CameraPermissionHelper
+import de.rki.coronawarnapp.util.ui.LazyString
 import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.popBackStack
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
@@ -68,6 +70,7 @@ class ScanCheckInQrCodeFragment :
                             .build()
                     )
                 }
+                is ScanCheckInQrCodeNavigation.InvalidQrCode -> showInvalidQrCodeInformation(navEvent.errorText)
             }
         }
     }
@@ -126,6 +129,20 @@ class ScanCheckInQrCodeFragment :
         DialogHelper.showDialog(permissionDeniedDialog)
     }
 
+    private fun showInvalidQrCodeInformation(lazyErrorText: LazyString) {
+        MaterialAlertDialogBuilder(requireContext()).apply {
+            val errorText = lazyErrorText.get(context)
+            setTitle(R.string.trace_location_attendee_invalid_qr_code_dialog_title)
+            setMessage(getString(R.string.trace_location_attendee_invalid_qr_code_dialog_message, errorText))
+            setPositiveButton(R.string.trace_location_attendee_invalid_qr_code_dialog_positive_button) { _, _ ->
+                startDecode()
+            }
+            setNegativeButton(R.string.trace_location_attendee_invalid_qr_code_dialog_negative_button) { _, _ ->
+                popBackStack()
+            }
+        }.show()
+    }
+
     private fun showCameraPermissionRationaleDialog() {
         val cameraPermissionRationaleDialogInstance = DialogHelper.DialogInstance(
             requireActivity(),
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt
index 688adc324d9c5747fea6216fad480c5f1ba6eb77..89b0b0571f8fa499817d09f235d1649477d6274b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt
@@ -1,6 +1,9 @@
 package de.rki.coronawarnapp.ui.presencetracing.attendee.scan
 
+import de.rki.coronawarnapp.util.ui.LazyString
+
 sealed class ScanCheckInQrCodeNavigation {
     object BackNavigation : ScanCheckInQrCodeNavigation()
+    data class InvalidQrCode(val errorText: LazyString) : ScanCheckInQrCodeNavigation()
     data class ScanResultNavigation(val uri: String) : ScanCheckInQrCodeNavigation()
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt
index c9227d4a526c385bb47403fa1e8a01c8b934c5b9..119e05465c7e07f5dc6deb40404804c7be2c8b17 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt
@@ -3,25 +3,45 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.scan
 import com.journeyapps.barcodescanner.BarcodeResult
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QRCodeUriParser
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocationVerifier
 import de.rki.coronawarnapp.util.permission.CameraSettings
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
+import de.rki.coronawarnapp.util.ui.toLazyString
+import de.rki.coronawarnapp.util.ui.toResolvingString
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
 import timber.log.Timber
 
 class ScanCheckInQrCodeViewModel @AssistedInject constructor(
-    private val cameraSettings: CameraSettings
+    private val qrCodeUriParser: QRCodeUriParser,
+    private val cameraSettings: CameraSettings,
+    private val traceLocationVerifier: TraceLocationVerifier
 ) : CWAViewModel() {
     val events = SingleLiveEvent<ScanCheckInQrCodeNavigation>()
 
     fun onNavigateUp() {
-        events.value = ScanCheckInQrCodeNavigation.BackNavigation
+        events.postValue(ScanCheckInQrCodeNavigation.BackNavigation)
     }
 
-    fun onScanResult(barcodeResult: BarcodeResult) {
-        events.value = ScanCheckInQrCodeNavigation.ScanResultNavigation(
-            barcodeResult.result.text
-        )
+    fun onScanResult(barcodeResult: BarcodeResult) = launch {
+        try {
+            Timber.i("uri: $barcodeResult.result.text")
+            val qrCodePayload = qrCodeUriParser.getQrCodePayload(barcodeResult.result.text)
+            when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) {
+                is TraceLocationVerifier.VerificationResult.Invalid ->
+                    events.postValue(
+                        ScanCheckInQrCodeNavigation.InvalidQrCode(
+                            verifyResult.errorTextRes.toResolvingString()
+                        )
+                    )
+                else -> events.postValue(ScanCheckInQrCodeNavigation.ScanResultNavigation(barcodeResult.result.text))
+            }
+        } catch (e: Exception) {
+            Timber.d(e, "TraceLocation verification failed")
+            val msg = e.message ?: "QR-Code was invalid"
+            events.postValue(ScanCheckInQrCodeNavigation.InvalidQrCode(msg.toLazyString()))
+        }
     }
 
     fun setCameraDeniedPermanently(denied: Boolean) {
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt
index 991ff951b66a1fbd02790442638020e2d403135c..065b85b7f36cc75781f53b78208ff919ec348c62 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt
@@ -1,14 +1,19 @@
 package de.rki.coronawarnapp.ui.presencetracing.attendee.scan
 
-import com.google.zxing.Result
 import com.journeyapps.barcodescanner.BarcodeResult
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QRCodeUriParser
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocationVerifier
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.ui.presencetracing.attendee.scan.ScanCheckInQrCodeNavigation.ScanResultNavigation
 import de.rki.coronawarnapp.util.permission.CameraSettings
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
+import io.mockk.coEvery
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.mockk
 import io.mockk.verify
+import kotlinx.coroutines.test.runBlockingTest
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
@@ -21,13 +26,17 @@ import testhelpers.preferences.mockFlowPreference
 class ScanCheckInQrCodeViewModelTest : BaseTest() {
 
     private lateinit var viewModel: ScanCheckInQrCodeViewModel
+    @MockK lateinit var qrCodeUriParser: QRCodeUriParser
     @MockK lateinit var cameraSettings: CameraSettings
+    @MockK lateinit var traceLocationVerifier: TraceLocationVerifier
 
     @BeforeEach
     fun setup() {
         MockKAnnotations.init(this)
         viewModel = ScanCheckInQrCodeViewModel(
-            cameraSettings
+            qrCodeUriParser,
+            cameraSettings,
+            traceLocationVerifier
         )
     }
 
@@ -38,15 +47,21 @@ class ScanCheckInQrCodeViewModelTest : BaseTest() {
     }
 
     @Test
-    fun `onScanResult results in navigation url`() {
-        val mockedResult = mockk<BarcodeResult>().apply {
-            every { result } returns mockk<Result>().apply {
-                every { text } returns "https://coronawarn.app/E1/SOME_PATH_GOES_HERE"
+    fun `onScanResult results in navigation url`() = runBlockingTest {
+        val codeContent = "https://coronawarn.app/E1/SOME_PATH_GOES_HERE"
+        val expectedOutcome: ScanCheckInQrCodeNavigation = ScanResultNavigation(codeContent)
+        val validationPassed = mockk<TraceLocationVerifier.VerificationResult.Valid>()
+        val mockedResult = mockk<BarcodeResult> {
+            every { result } returns mockk {
+                every { text } returns codeContent
             }
         }
+        val qrCodePayload = mockk<TraceLocationOuterClass.QRCodePayload>()
+        coEvery { qrCodeUriParser.getQrCodePayload(any()) } returns qrCodePayload
+        every { traceLocationVerifier.verifyTraceLocation(qrCodePayload) } returns validationPassed
+
         viewModel.onScanResult(mockedResult)
-        viewModel.events.getOrAwaitValue() shouldBe
-            ScanCheckInQrCodeNavigation.ScanResultNavigation("https://coronawarn.app/E1/SOME_PATH_GOES_HERE")
+        viewModel.events.getOrAwaitValue() shouldBe expectedOutcome
     }
 
     @Test