diff --git a/app/src/main/java/im/vector/riotredesign/core/utils/FragmentArgumentDelegate.kt b/app/src/main/java/im/vector/riotredesign/core/utils/FragmentArgumentDelegate.kt
index 28a5419817..565c421cae 100644
--- a/app/src/main/java/im/vector/riotredesign/core/utils/FragmentArgumentDelegate.kt
+++ b/app/src/main/java/im/vector/riotredesign/core/utils/FragmentArgumentDelegate.kt
@@ -6,21 +6,22 @@ import android.support.v4.app.BundleCompat
 import android.support.v4.app.Fragment
 import kotlin.reflect.KProperty
 
-class FragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fragment, T> {
+class FragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fragment, T?> {
 
     var value: T? = null
 
-    override operator fun getValue(thisRef: android.support.v4.app.Fragment, property: kotlin.reflect.KProperty<*>): T {
+    override operator fun getValue(thisRef: android.support.v4.app.Fragment, property: kotlin.reflect.KProperty<*>): T? {
         if (value == null) {
             val args = thisRef.arguments
-                       ?: throw IllegalStateException("Cannot read property ${property.name} if no arguments have been set")
             @Suppress("UNCHECKED_CAST")
-            value = args.get(property.name) as T
+            value = args?.get(property.name) as T?
         }
-        return value ?: throw IllegalStateException("Property ${property.name} could not be read")
+        return value
     }
 
-    override operator fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
+    override operator fun setValue(thisRef: Fragment, property: KProperty<*>, value: T?) {
+        if (value == null) return
+
         if (thisRef.arguments == null) {
             thisRef.arguments = Bundle()
         }
@@ -42,7 +43,21 @@ class FragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fr
             is Binder                -> BundleCompat.putBinder(args, key, value)
             is android.os.Parcelable -> args.putParcelable(key, value)
             is java.io.Serializable  -> args.putSerializable(key, value)
-            else                     -> throw IllegalStateException("Type ${value.javaClass.canonicalName} of property ${property.name} is not supported")
+            else                     -> throw IllegalStateException("Type ${value.javaClass.name} of property ${property.name} is not supported")
         }
     }
-} 
\ No newline at end of file
+}
+
+class UnsafeFragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fragment, T> {
+
+    private val innerDelegate = FragmentArgumentDelegate<T>()
+
+    override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
+        innerDelegate.setValue(thisRef, property, value)
+    }
+
+    override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
+        return innerDelegate.getValue(thisRef, property)!!
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
index b921100379..4775bb0cbc 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
@@ -15,6 +15,7 @@ import im.vector.riotredesign.R
 import im.vector.riotredesign.core.platform.RiotFragment
 import im.vector.riotredesign.core.platform.ToolbarConfigurable
 import im.vector.riotredesign.core.utils.FragmentArgumentDelegate
+import im.vector.riotredesign.core.utils.UnsafeFragmentArgumentDelegate
 import im.vector.riotredesign.features.home.AvatarRenderer
 import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
 import kotlinx.android.synthetic.main.fragment_room_detail.*
@@ -25,16 +26,18 @@ class RoomDetailFragment : RiotFragment() {
 
     companion object {
 
-        fun newInstance(roomId: String): RoomDetailFragment {
+        fun newInstance(roomId: String, eventId: String? = null): RoomDetailFragment {
             return RoomDetailFragment().apply {
                 this.roomId = roomId
+                this.eventId = eventId
             }
         }
     }
 
     private val matrix by inject<Matrix>()
     private val currentSession = matrix.currentSession
-    private var roomId by FragmentArgumentDelegate<String>()
+    private var roomId: String by UnsafeFragmentArgumentDelegate()
+    private var eventId: String? by FragmentArgumentDelegate()
     private val timelineEventController by inject<TimelineEventController>(parameters = { ParameterList(roomId) })
     private lateinit var room: Room
 
@@ -48,7 +51,7 @@ class RoomDetailFragment : RiotFragment() {
         setupRecyclerView()
         setupToolbar()
         room.loadRoomMembersIfNeeded()
-        room.liveTimeline().observe(this, Observer { renderEvents(it) })
+        room.timeline(eventId).observe(this, Observer { renderEvents(it) })
         room.roomSummary.observe(this, Observer { renderRoomSummary(it) })
         sendButton.setOnClickListener {
             val textMessage = composerEditText.text.toString()
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/TimelineHolder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/TimelineHolder.kt
index 535f681a71..fc01a47b59 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/TimelineHolder.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/TimelineHolder.kt
@@ -6,6 +6,6 @@ import im.vector.matrix.android.api.session.events.model.EnrichedEvent
 
 interface TimelineHolder {
 
-    fun liveTimeline(): LiveData<PagedList<EnrichedEvent>>
+    fun timeline(eventId: String? = null): LiveData<PagedList<EnrichedEvent>>
 
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt
index a9210550bb..07316c10f1 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt
@@ -12,8 +12,10 @@ import im.vector.matrix.android.internal.session.room.timeline.PaginationDirecti
 internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
                                direction: PaginationDirection) {
 
-    val events = chunkEntity.events.map { it.asDomain() }
-    addAll(events, direction)
+
+    chunkEntity.events.forEach {
+        addOrUpdate(it.asDomain(), direction)
+    }
     if (direction == PaginationDirection.FORWARDS) {
         nextToken = chunkEntity.nextToken
     } else {
@@ -26,15 +28,13 @@ internal fun ChunkEntity.addAll(events: List<Event>,
                                 updateStateIndex: Boolean = true) {
 
     events.forEach { event ->
-        if (updateStateIndex && event.isStateEvent()) {
-            updateStateIndex(direction)
-        }
-        addOrUpdate(event, direction)
+        addOrUpdate(event, direction, updateStateIndex)
     }
 }
 
 internal fun ChunkEntity.addOrUpdate(event: Event,
-                                     direction: PaginationDirection) {
+                                     direction: PaginationDirection,
+                                     updateStateIndex: Boolean = true) {
     if (!isManaged) {
         throw IllegalStateException("Chunk entity should be managed to use fast contains")
     }
@@ -43,6 +43,10 @@ internal fun ChunkEntity.addOrUpdate(event: Event,
         return
     }
 
+    if (updateStateIndex && event.isStateEvent()) {
+        updateStateIndex(direction)
+    }
+
     val currentStateIndex = stateIndex(direction)
     if (!events.fastContains(event.eventId)) {
         val eventEntity = event.asEntity()
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt
index 1388c14140..07b8a9fe5d 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt
@@ -46,8 +46,8 @@ internal data class DefaultRoom(
         }
     }
 
-    override fun liveTimeline(): LiveData<PagedList<EnrichedEvent>> {
-        return timelineHolder.liveTimeline()
+    override fun timeline(eventId: String?): LiveData<PagedList<EnrichedEvent>> {
+        return timelineHolder.timeline(eventId)
     }
 
     override fun loadRoomMembersIfNeeded(): Cancelable {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt
index 655cd33d1a..31311bcdab 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt
@@ -1,9 +1,11 @@
 package im.vector.matrix.android.internal.session.room
 
+import im.vector.matrix.android.api.session.events.model.Event
 import im.vector.matrix.android.api.session.room.model.MessageContent
 import im.vector.matrix.android.internal.network.NetworkConstants
 import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse
 import im.vector.matrix.android.internal.session.room.send.SendResponse
+import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse
 import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEvent
 import retrofit2.Call
 import retrofit2.http.Body
@@ -63,5 +65,28 @@ internal interface RoomAPI {
              @Body content: MessageContent
     ): Call<SendResponse>
 
+    /**
+     * Get the context surrounding an event.
+     *
+     * @param roomId  the room id
+     * @param eventId the event Id
+     * @param limit   the maximum number of messages to retrieve
+     * @param filter  A JSON RoomEventFilter to filter returned events with. Optional.
+     */
+    @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/context/{eventId}")
+    fun getContextOfEvent(@Path("roomId") roomId: String,
+                          @Path("eventId") eventId: String,
+                          @Query("limit") limit: Int,
+                          @Query("filter") filter: String? = null): Call<EventContextResponse>
+
+    /**
+     * Retrieve an event from its room id / events id
+     *
+     * @param roomId  the room id
+     * @param eventId the event Id
+     */
+    @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/event/{eventId}")
+    fun getEvent(@Path("roomId") roomId: String, @Path("eventId") eventId: String): Call<Event>
+
 
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineHolder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineHolder.kt
index 21095bcd39..ca7299db4c 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineHolder.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineHolder.kt
@@ -13,6 +13,8 @@ import im.vector.matrix.android.internal.database.model.EventEntity
 import im.vector.matrix.android.internal.database.model.EventEntityFields
 import im.vector.matrix.android.internal.database.query.where
 import im.vector.matrix.android.internal.session.events.interceptor.MessageEventInterceptor
+import io.realm.Realm
+import io.realm.RealmQuery
 
 private const val PAGE_SIZE = 30
 
@@ -28,12 +30,12 @@ internal class DefaultTimelineHolder(private val roomId: String,
         eventInterceptors.add(MessageEventInterceptor(monarchy, roomId))
     }
 
-    override fun liveTimeline(): LiveData<PagedList<EnrichedEvent>> {
-        val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
-            EventEntity
-                    .where(realm, roomId = roomId)
-                    .equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.IS_LAST}", true)
-                    .sort(EventEntityFields.DISPLAY_INDEX)
+    override fun timeline(eventId: String?): LiveData<PagedList<EnrichedEvent>> {
+        if (eventId != null) {
+            fetchEventIfNeeded()
+        }
+        val realmDataSourceFactory = monarchy.createDataSourceFactory {
+            buildDataSourceFactoryQuery(it, eventId)
         }
         val domainSourceFactory = realmDataSourceFactory
                 .map { it.asDomain() }
@@ -59,4 +61,23 @@ internal class DefaultTimelineHolder(private val roomId: String,
         val livePagedListBuilder = LivePagedListBuilder(domainSourceFactory, pagedListConfig).setBoundaryCallback(boundaryCallback)
         return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
     }
+
+    private fun fetchEventIfNeeded() {
+
+    }
+
+    private fun buildDataSourceFactoryQuery(realm: Realm, eventId: String?): RealmQuery<EventEntity> {
+        val query = if (eventId == null) {
+            EventEntity
+                    .where(realm, roomId = roomId)
+                    .equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.IS_LAST}", true)
+        } else {
+            EventEntity
+                    .where(realm, roomId = roomId)
+                    .`in`("${EventEntityFields.CHUNK}.${ChunkEntityFields.EVENTS.EVENT_ID}", arrayOf(eventId))
+        }
+        return query.sort(EventEntityFields.DISPLAY_INDEX)
+    }
+
+
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/EventContextResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/EventContextResponse.kt
new file mode 100644
index 0000000000..79cfac72c9
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/EventContextResponse.kt
@@ -0,0 +1,22 @@
+package im.vector.matrix.android.internal.session.room.timeline
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import im.vector.matrix.android.api.session.events.model.Event
+
+@JsonClass(generateAdapter = true)
+data class EventContextResponse(
+        @Json(name = "event") val event: Event,
+        @Json(name = "start") val prevToken: String? = null,
+        @Json(name = "events_before") val eventsBefore: List<Event> = emptyList(),
+        @Json(name = "events_after") val eventsAfter: List<Event> = emptyList(),
+        @Json(name = "end") val nextToken: String? = null,
+        @Json(name = "state") val stateEvents: List<Event> = emptyList()
+) {
+
+    val timelineEvents: List<Event> by lazy {
+        eventsBefore + event + eventsAfter
+    }
+
+
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt
new file mode 100644
index 0000000000..fcab9e8297
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt
@@ -0,0 +1,102 @@
+package im.vector.matrix.android.internal.session.room.timeline
+
+import arrow.core.Try
+import com.zhuinden.monarchy.Monarchy
+import im.vector.matrix.android.api.MatrixCallback
+import im.vector.matrix.android.api.util.Cancelable
+import im.vector.matrix.android.internal.database.helper.addAll
+import im.vector.matrix.android.internal.database.helper.addOrUpdate
+import im.vector.matrix.android.internal.database.helper.deleteOnCascade
+import im.vector.matrix.android.internal.database.helper.merge
+import im.vector.matrix.android.internal.database.model.ChunkEntity
+import im.vector.matrix.android.internal.database.model.RoomEntity
+import im.vector.matrix.android.internal.database.query.find
+import im.vector.matrix.android.internal.database.query.where
+import im.vector.matrix.android.internal.legacy.util.FilterUtil
+import im.vector.matrix.android.internal.network.executeRequest
+import im.vector.matrix.android.internal.session.room.RoomAPI
+import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
+import im.vector.matrix.android.internal.util.CancelableCoroutine
+import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
+import im.vector.matrix.android.internal.util.tryTransactionSync
+import io.realm.kotlin.createObject
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+internal class GetContextOfEventRequest(private val roomAPI: RoomAPI,
+                                        private val monarchy: Monarchy,
+                                        private val coroutineDispatchers: MatrixCoroutineDispatchers,
+                                        private val stateEventsChunkHandler: StateEventsChunkHandler
+) {
+
+    fun execute(roomId: String,
+                eventId: String,
+                callback: MatrixCallback<EventContextResponse>
+    ): Cancelable {
+        val job = GlobalScope.launch(coroutineDispatchers.main) {
+            val filter = FilterUtil.createRoomEventFilter(true)?.toJSONString()
+            val contextOrFailure = execute(roomId, eventId, filter)
+            contextOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(it) })
+        }
+        return CancelableCoroutine(job)
+    }
+
+    private suspend fun execute(roomId: String,
+                                eventId: String,
+                                filter: String?) = withContext(coroutineDispatchers.io) {
+
+        executeRequest<EventContextResponse> {
+            apiCall = roomAPI.getContextOfEvent(roomId, eventId, 1, filter)
+        }.flatMap { response ->
+            insertInDb(response, roomId)
+        }
+    }
+
+    private fun insertInDb(response: EventContextResponse, roomId: String): Try<EventContextResponse> {
+        return monarchy
+                .tryTransactionSync { realm ->
+                    val roomEntity = RoomEntity.where(realm, roomId).findFirst()
+                                     ?: throw IllegalStateException("You shouldn't use this method without a room")
+
+                    val currentChunk = realm.createObject<ChunkEntity>().apply {
+                        prevToken = response.prevToken
+                        nextToken = response.nextToken
+                    }
+
+                    currentChunk.addOrUpdate(response.event, PaginationDirection.FORWARDS)
+                    currentChunk.addAll(response.eventsAfter, PaginationDirection.FORWARDS)
+                    currentChunk.addAll(response.eventsBefore, PaginationDirection.BACKWARDS)
+
+                    // Now, handles chunk merge
+                    val prevChunk = ChunkEntity.find(realm, roomId, nextToken = response.prevToken)
+                    val nextChunk = ChunkEntity.find(realm, roomId, prevToken = response.nextToken)
+
+                    if (prevChunk != null) {
+                        currentChunk.merge(prevChunk, PaginationDirection.BACKWARDS)
+                        roomEntity.deleteOnCascade(prevChunk)
+                    }
+                    if (nextChunk != null) {
+                        currentChunk.merge(nextChunk, PaginationDirection.FORWARDS)
+                        roomEntity.deleteOnCascade(nextChunk)
+                    }
+                    /*
+                    val eventIds = response.timelineEvents.mapNotNull { it.eventId }
+                    ChunkEntity
+                            .findAllIncludingEvents(realm, eventIds)
+                            .filter { it != currentChunk }
+                            .forEach { overlapped ->
+                                currentChunk.merge(overlapped, direction)
+                                roomEntity.deleteOnCascade(overlapped)
+                            }
+                    */
+                    roomEntity.addOrUpdate(currentChunk)
+
+                    val stateEventsChunk = stateEventsChunkHandler.handle(realm, roomId, response.stateEvents)
+                    roomEntity.addOrUpdate(stateEventsChunk)
+                }
+                .map { response }
+    }
+
+
+}
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventRequest.kt
new file mode 100644
index 0000000000..1a8ebc7b3b
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventRequest.kt
@@ -0,0 +1,41 @@
+package im.vector.matrix.android.internal.session.room.timeline
+
+import com.zhuinden.monarchy.Monarchy
+import im.vector.matrix.android.api.MatrixCallback
+import im.vector.matrix.android.api.session.events.model.Event
+import im.vector.matrix.android.api.util.Cancelable
+import im.vector.matrix.android.internal.network.executeRequest
+import im.vector.matrix.android.internal.session.room.RoomAPI
+import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
+import im.vector.matrix.android.internal.util.CancelableCoroutine
+import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+internal class GetEventRequest(private val roomAPI: RoomAPI,
+                               private val monarchy: Monarchy,
+                               private val coroutineDispatchers: MatrixCoroutineDispatchers,
+                               private val stateEventsChunkHandler: StateEventsChunkHandler
+) {
+
+    fun execute(roomId: String,
+                eventId: String,
+                callback: MatrixCallback<Event>
+    ): Cancelable {
+        val job = GlobalScope.launch(coroutineDispatchers.main) {
+            val eventOrFailure = execute(roomId, eventId)
+            eventOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(it) })
+        }
+        return CancelableCoroutine(job)
+    }
+
+    private suspend fun execute(roomId: String,
+                                eventId: String) = withContext(coroutineDispatchers.io) {
+
+        executeRequest<Event> {
+            apiCall = roomAPI.getEvent(roomId, eventId)
+        }
+    }
+
+}
\ No newline at end of file