diff --git a/Cargo.lock b/Cargo.lock
index eebaddc0a15019bb5e68a3a240eb761a8fe1a27f..c88c5786d7292e265fd42c0971942ca4084cc967 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1631,7 +1631,6 @@ dependencies = [
 [[package]]
 name = "ruma"
 version = "0.0.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "ruma-api",
  "ruma-appservice-api",
@@ -1647,7 +1646,6 @@ dependencies = [
 [[package]]
 name = "ruma-api"
 version = "0.17.0-alpha.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "http",
  "percent-encoding",
@@ -1662,7 +1660,6 @@ dependencies = [
 [[package]]
 name = "ruma-api-macros"
 version = "0.17.0-alpha.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -1673,7 +1670,6 @@ dependencies = [
 [[package]]
 name = "ruma-appservice-api"
 version = "0.2.0-alpha.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "ruma-api",
  "ruma-common",
@@ -1686,7 +1682,6 @@ dependencies = [
 [[package]]
 name = "ruma-client-api"
 version = "0.10.0-alpha.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "assign",
  "http",
@@ -1705,9 +1700,9 @@ dependencies = [
 [[package]]
 name = "ruma-common"
 version = "0.2.0"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "js_int",
+ "ruma-api",
  "ruma-identifiers",
  "ruma-serde",
  "serde",
@@ -1718,7 +1713,6 @@ dependencies = [
 [[package]]
 name = "ruma-events"
 version = "0.22.0-alpha.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "js_int",
  "ruma-common",
@@ -1733,7 +1727,6 @@ dependencies = [
 [[package]]
 name = "ruma-events-macros"
 version = "0.22.0-alpha.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -1744,7 +1737,6 @@ dependencies = [
 [[package]]
 name = "ruma-federation-api"
 version = "0.0.3"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "js_int",
  "ruma-api",
@@ -1759,7 +1751,6 @@ dependencies = [
 [[package]]
 name = "ruma-identifiers"
 version = "0.17.4"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "rand",
  "ruma-identifiers-macros",
@@ -1771,7 +1762,6 @@ dependencies = [
 [[package]]
 name = "ruma-identifiers-macros"
 version = "0.17.4"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1782,18 +1772,14 @@ dependencies = [
 [[package]]
 name = "ruma-identifiers-validation"
 version = "0.1.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
- "ruma-serde",
  "serde",
- "serde_json",
  "strum",
 ]
 
 [[package]]
 name = "ruma-serde"
 version = "0.2.3"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "form_urlencoded",
  "itoa",
@@ -1805,7 +1791,6 @@ dependencies = [
 [[package]]
 name = "ruma-signatures"
 version = "0.6.0-dev.1"
-source = "git+https://github.com/ruma/ruma?rev=aff914050eb297bd82b8aafb12158c88a9e480e1#aff914050eb297bd82b8aafb12158c88a9e480e1"
 dependencies = [
  "base64",
  "ring",
@@ -2070,7 +2055,6 @@ checksum = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
 [[package]]
 name = "state-res"
 version = "0.1.0"
-source = "git+https://github.com/ruma/state-res?branch=spec-comp#394d26744a6586ccdc01838964bb27dab289eee5"
 dependencies = [
  "itertools",
  "js_int",
diff --git a/Cargo.toml b/Cargo.toml
index 15cee725907dccb414852816b1838bd97e1f67ea..5d35433382b379a83cb2d0b8d39f695d5a8ad0e4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,8 +15,9 @@ edition = "2018"
 # TODO: This can become optional as soon as proper configs are supported
 #rocket = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "8d779caa22c63b15a6c3ceb75d8f6d4971b2eb67", features = ["tls"] } # Used to handle requests
 rocket = { git = "https://github.com/timokoesters/Rocket.git", branch = "empty_parameters", features = ["tls"] }
-
-ruma = { git = "https://github.com/ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], rev = "aff914050eb297bd82b8aafb12158c88a9e480e1" } # Used for matrix spec type definitions and helpers
+#ruma = { git = "https://github.com/ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], rev = "aff914050eb297bd82b8aafb12158c88a9e480e1" } # Used for matrix spec type definitions and helpers
+#ruma = { git = "https://github.com/timokoesters/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], branch = "timo-fixes" } # Used for matrix spec type definitions and helpers
+ruma = { path = "../ruma/ruma", features = ["unstable-exhaustive-types", "rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"] }
 tokio = "0.2.22" # Used for long polling
 sled = "0.32.0" # Used for storing data permanently
 log = "0.4.8" # Used for emitting log entries
@@ -31,8 +32,8 @@ reqwest = "0.10.6" # Used to send requests
 thiserror = "1.0.19" # Used for conduit::Error type
 image = { version = "0.23.4", default-features = false, features = ["jpeg", "png", "gif"] } # Used to generate thumbnails for images
 base64 = "0.12.3" # Used to encode server public key
-# state-res = { path = "../../state-res" }
-state-res = { git = "https://github.com/ruma/state-res", version = "0.1.0", branch = "spec-comp" }
+#state-res = { git = "https://github.com/ruma/state-res", version = "0.1.0", branch = "spec-comp" }
+state-res = { path = "../state-res" }
 ring = "0.16.15"
 
 [features]
diff --git a/src/client_server/account.rs b/src/client_server/account.rs
index 9e52f6d23181d1c1ea00a74804bb48faf9ab7787..cb77a15d4d6ef87eddeaa5e7503ae8208c0386f6 100644
--- a/src/client_server/account.rs
+++ b/src/client_server/account.rs
@@ -33,7 +33,7 @@
 )]
 pub fn get_register_available_route(
     db: State<'_, Database>,
-    body: Ruma<get_username_availability::Request>,
+    body: Ruma<get_username_availability::Request<'_>>,
 ) -> ConduitResult<get_username_availability::Response> {
     // Validate user id
     let user_id = UserId::parse_with_server_name(body.username.clone(), db.globals.server_name())
@@ -75,7 +75,7 @@ pub fn get_register_available_route(
 )]
 pub fn register_route(
     db: State<'_, Database>,
-    body: Ruma<register::IncomingRequest>,
+    body: Ruma<register::Request<'_>>,
 ) -> ConduitResult<register::Response> {
     if db.globals.registration_disabled() {
         return Err(Error::BadRequest(
@@ -84,7 +84,7 @@ pub fn register_route(
         ));
     }
 
-    let is_guest = matches!(body.kind, Some(RegistrationKind::Guest));
+    let is_guest = body.kind == RegistrationKind::Guest;
 
     let mut missing_username = false;
 
@@ -223,7 +223,7 @@ pub fn register_route(
 )]
 pub fn change_password_route(
     db: State<'_, Database>,
-    body: Ruma<change_password::IncomingRequest>,
+    body: Ruma<change_password::Request<'_>>,
 ) -> ConduitResult<change_password::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     let device_id = body.device_id.as_ref().expect("user is authenticated");
@@ -305,7 +305,7 @@ pub fn whoami_route(body: Ruma<whoami::Request>) -> ConduitResult<whoami::Respon
 )]
 pub fn deactivate_route(
     db: State<'_, Database>,
-    body: Ruma<deactivate::IncomingRequest>,
+    body: Ruma<deactivate::Request<'_>>,
 ) -> ConduitResult<deactivate::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     let device_id = body.device_id.as_ref().expect("user is authenticated");
diff --git a/src/client_server/alias.rs b/src/client_server/alias.rs
index 669f558d636b658a5987e2578e54ec90c1ae5ada..1d30261b686d4e76524474b9a4bd9a157e2e2814 100644
--- a/src/client_server/alias.rs
+++ b/src/client_server/alias.rs
@@ -20,7 +20,7 @@
 )]
 pub fn create_alias_route(
     db: State<'_, Database>,
-    body: Ruma<create_alias::IncomingRequest>,
+    body: Ruma<create_alias::Request<'_>>,
 ) -> ConduitResult<create_alias::Response> {
     if db.rooms.id_from_alias(&body.room_alias)?.is_some() {
         return Err(Error::Conflict("Alias already exists."));
@@ -38,7 +38,7 @@ pub fn create_alias_route(
 )]
 pub fn delete_alias_route(
     db: State<'_, Database>,
-    body: Ruma<delete_alias::IncomingRequest>,
+    body: Ruma<delete_alias::Request<'_>>,
 ) -> ConduitResult<delete_alias::Response> {
     db.rooms.set_alias(&body.room_alias, None, &db.globals)?;
 
@@ -51,7 +51,7 @@ pub fn delete_alias_route(
 )]
 pub async fn get_alias_route(
     db: State<'_, Database>,
-    body: Ruma<get_alias::IncomingRequest>,
+    body: Ruma<get_alias::Request<'_>>,
 ) -> ConduitResult<get_alias::Response> {
     get_alias_helper(&db, &body.room_alias).await
 }
@@ -65,7 +65,7 @@ pub async fn get_alias_helper(
             &db,
             room_alias.server_name().to_string(),
             federation::query::get_room_information::v1::Request {
-                room_alias: room_alias.to_string(),
+                room_alias,
             },
         )
         .await?;
diff --git a/src/client_server/backup.rs b/src/client_server/backup.rs
index a10496494eca65ba1a917ae6cefef02b658f1e21..8966c017c04463fa1d08a578dd89791eb325e401 100644
--- a/src/client_server/backup.rs
+++ b/src/client_server/backup.rs
@@ -33,7 +33,7 @@ pub fn create_backup_route(
 )]
 pub fn update_backup_route(
     db: State<'_, Database>,
-    body: Ruma<update_backup::Request>,
+    body: Ruma<update_backup::Request<'_>>,
 ) -> ConduitResult<update_backup::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     db.key_backups
@@ -75,7 +75,7 @@ pub fn get_latest_backup_route(
 )]
 pub fn get_backup_route(
     db: State<'_, Database>,
-    body: Ruma<get_backup::Request>,
+    body: Ruma<get_backup::Request<'_>>,
 ) -> ConduitResult<get_backup::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     let algorithm = db
@@ -90,7 +90,7 @@ pub fn get_backup_route(
         algorithm,
         count: (db.key_backups.count_keys(sender_id, &body.version)? as u32).into(),
         etag: db.key_backups.get_etag(sender_id, &body.version)?,
-        version: body.version.clone(),
+        version: body.version.to_owned(),
     }
     .into())
 }
@@ -102,7 +102,7 @@ pub fn get_backup_route(
 )]
 pub fn add_backup_keys_route(
     db: State<'_, Database>,
-    body: Ruma<add_backup_keys::Request>,
+    body: Ruma<add_backup_keys::Request<'_>>,
 ) -> ConduitResult<add_backup_keys::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -132,7 +132,7 @@ pub fn add_backup_keys_route(
 )]
 pub fn get_backup_keys_route(
     db: State<'_, Database>,
-    body: Ruma<get_backup_keys::Request>,
+    body: Ruma<get_backup_keys::Request<'_>>,
 ) -> ConduitResult<get_backup_keys::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/config.rs b/src/client_server/config.rs
index baa9381ba7ef056b927e01aacacaace14bc2d374..515ad16075174f97eb0423d1dedc5d19408105c2 100644
--- a/src/client_server/config.rs
+++ b/src/client_server/config.rs
@@ -18,7 +18,7 @@
 )]
 pub fn set_global_account_data_route(
     db: State<'_, Database>,
-    body: Ruma<set_global_account_data::Request>,
+    body: Ruma<set_global_account_data::Request<'_>>,
 ) -> ConduitResult<set_global_account_data::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -49,7 +49,7 @@ pub fn set_global_account_data_route(
 )]
 pub fn get_global_account_data_route(
     db: State<'_, Database>,
-    body: Ruma<get_global_account_data::Request>,
+    body: Ruma<get_global_account_data::Request<'_>>,
 ) -> ConduitResult<get_global_account_data::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/context.rs b/src/client_server/context.rs
index 7b1fad917ed4b9fbabc1e068558175a46d2d1c8b..959372646e7972350f9a7bc839ed8b401c778044 100644
--- a/src/client_server/context.rs
+++ b/src/client_server/context.rs
@@ -12,7 +12,7 @@
 )]
 pub fn get_context_route(
     db: State<'_, Database>,
-    body: Ruma<get_context::IncomingRequest>,
+    body: Ruma<get_context::Request<'_>>,
 ) -> ConduitResult<get_context::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/device.rs b/src/client_server/device.rs
index 89033f06f8b55537840e9dfc022299f60465aa95..6352d0d1d4f84574016f0fe178dfb3d8550d71fb 100644
--- a/src/client_server/device.rs
+++ b/src/client_server/device.rs
@@ -37,7 +37,7 @@ pub fn get_devices_route(
 )]
 pub fn get_device_route(
     db: State<'_, Database>,
-    body: Ruma<get_device::IncomingRequest>,
+    body: Ruma<get_device::Request<'_>>,
     _device_id: String,
 ) -> ConduitResult<get_device::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
@@ -56,7 +56,7 @@ pub fn get_device_route(
 )]
 pub fn update_device_route(
     db: State<'_, Database>,
-    body: Ruma<update_device::IncomingRequest>,
+    body: Ruma<update_device::Request<'_>>,
     _device_id: String,
 ) -> ConduitResult<update_device::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
@@ -80,7 +80,7 @@ pub fn update_device_route(
 )]
 pub fn delete_device_route(
     db: State<'_, Database>,
-    body: Ruma<delete_device::IncomingRequest>,
+    body: Ruma<delete_device::Request<'_>>,
     _device_id: String,
 ) -> ConduitResult<delete_device::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
@@ -127,7 +127,7 @@ pub fn delete_device_route(
 )]
 pub fn delete_devices_route(
     db: State<'_, Database>,
-    body: Ruma<delete_devices::IncomingRequest>,
+    body: Ruma<delete_devices::Request<'_>>,
 ) -> ConduitResult<delete_devices::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     let device_id = body.device_id.as_ref().expect("user is authenticated");
diff --git a/src/client_server/directory.rs b/src/client_server/directory.rs
index 3b1068668282727e3e491242a4dddd6c47a7073e..34feb71804e3803ba3c6117ae38860c23f202915 100644
--- a/src/client_server/directory.rs
+++ b/src/client_server/directory.rs
@@ -14,7 +14,7 @@
         },
         federation,
     },
-    directory::{Filter, PublicRoomsChunk, RoomNetwork},
+    directory::{IncomingFilter, PublicRoomsChunk, IncomingRoomNetwork},
     events::{
         room::{avatar, canonical_alias, guest_access, history_visibility, name, topic},
         EventType,
@@ -31,7 +31,7 @@
 )]
 pub async fn get_public_rooms_filtered_route(
     db: State<'_, Database>,
-    body: Ruma<get_public_rooms_filtered::IncomingRequest>,
+    body: Ruma<get_public_rooms_filtered::Request<'_>>,
 ) -> ConduitResult<get_public_rooms_filtered::Response> {
     let Ruma {
         body:
@@ -61,7 +61,7 @@ pub async fn get_public_rooms_filtered_route(
 )]
 pub async fn get_public_rooms_route(
     db: State<'_, Database>,
-    body: Ruma<get_public_rooms::IncomingRequest>,
+    body: Ruma<get_public_rooms::Request<'_>>,
 ) -> ConduitResult<get_public_rooms::Response> {
     let response = get_public_rooms_filtered_helper(
         &db,
@@ -89,7 +89,7 @@ pub async fn get_public_rooms_route(
 )]
 pub async fn set_room_visibility_route(
     db: State<'_, Database>,
-    body: Ruma<set_room_visibility::Request>,
+    body: Ruma<set_room_visibility::Request<'_>>,
 ) -> ConduitResult<set_room_visibility::Response> {
     match body.visibility {
         room::Visibility::Public => db.rooms.set_public(&body.room_id, true)?,
@@ -105,7 +105,7 @@ pub async fn set_room_visibility_route(
 )]
 pub async fn get_room_visibility_route(
     db: State<'_, Database>,
-    body: Ruma<get_room_visibility::Request>,
+    body: Ruma<get_room_visibility::Request<'_>>,
 ) -> ConduitResult<get_room_visibility::Response> {
     Ok(get_room_visibility::Response {
         visibility: if db.rooms.is_public_room(&body.room_id)? {
@@ -122,8 +122,8 @@ pub async fn get_public_rooms_filtered_helper(
     server: Option<&str>,
     limit: Option<js_int::UInt>,
     since: Option<&str>,
-    _filter: Option<Filter>,
-    _network: Option<RoomNetwork>,
+    _filter: Option<IncomingFilter>,
+    _network: Option<IncomingRoomNetwork>,
 ) -> ConduitResult<get_public_rooms_filtered::Response> {
     if let Some(other_server) = server
         .clone()
diff --git a/src/client_server/filter.rs b/src/client_server/filter.rs
index 4322de3e5052fc995465f64586ffb9be12692e65..4b1c3a000e2f1a058e6db26a3f986f95730d523a 100644
--- a/src/client_server/filter.rs
+++ b/src/client_server/filter.rs
@@ -7,7 +7,7 @@
 #[cfg_attr(feature = "conduit_bin", get("/_matrix/client/r0/user/<_>/filter/<_>"))]
 pub fn get_filter_route() -> ConduitResult<get_filter::Response> {
     // TODO
-    Ok(get_filter::Response::new(filter::FilterDefinition {
+    Ok(get_filter::Response::new(filter::IncomingFilterDefinition {
         event_fields: None,
         event_format: None,
         account_data: None,
diff --git a/src/client_server/keys.rs b/src/client_server/keys.rs
index 33115296439cd16c70719f8e4302953cbe2fd5b7..0e7b1eff1623ed6d9fc485761bfddd59e023a60f 100644
--- a/src/client_server/keys.rs
+++ b/src/client_server/keys.rs
@@ -11,7 +11,7 @@
             uiaa::{AuthFlow, UiaaInfo},
         },
     },
-    encryption::UnsignedDeviceInfo,
+    encryption::IncomingUnsignedDeviceInfo,
 };
 use std::collections::{BTreeMap, HashSet};
 
@@ -24,7 +24,7 @@
 )]
 pub fn upload_keys_route(
     db: State<'_, Database>,
-    body: Ruma<upload_keys::Request>,
+    body: Ruma<upload_keys::Request<'_>>,
 ) -> ConduitResult<upload_keys::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     let device_id = body.device_id.as_ref().expect("user is authenticated");
@@ -56,7 +56,7 @@ pub fn upload_keys_route(
 )]
 pub fn get_keys_route(
     db: State<'_, Database>,
-    body: Ruma<get_keys::IncomingRequest>,
+    body: Ruma<get_keys::Request<'_>>,
 ) -> ConduitResult<get_keys::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -78,9 +78,9 @@ pub fn get_keys_route(
                             Error::bad_database("all_device_keys contained nonexistent device.")
                         })?;
 
-                    keys.unsigned = Some(UnsignedDeviceInfo {
+                    keys.unsigned = IncomingUnsignedDeviceInfo {
                         device_display_name: metadata.display_name,
-                    });
+                    };
 
                     container.insert(device_id, keys);
                 }
@@ -97,9 +97,9 @@ pub fn get_keys_route(
                         ),
                     )?;
 
-                    keys.unsigned = Some(UnsignedDeviceInfo {
+                    keys.unsigned = IncomingUnsignedDeviceInfo {
                         device_display_name: metadata.display_name,
-                    });
+                    };
 
                     container.insert(device_id.clone(), keys);
                 }
@@ -167,7 +167,7 @@ pub fn claim_keys_route(
 )]
 pub fn upload_signing_keys_route(
     db: State<'_, Database>,
-    body: Ruma<upload_signing_keys::IncomingRequest>,
+    body: Ruma<upload_signing_keys::Request<'_>>,
 ) -> ConduitResult<upload_signing_keys::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     let device_id = body.device_id.as_ref().expect("user is authenticated");
@@ -280,7 +280,7 @@ pub fn upload_signatures_route(
 )]
 pub fn get_key_changes_route(
     db: State<'_, Database>,
-    body: Ruma<get_key_changes::IncomingRequest>,
+    body: Ruma<get_key_changes::Request<'_>>,
 ) -> ConduitResult<get_key_changes::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/media.rs b/src/client_server/media.rs
index 79c1f080ae30ffa1fd2efc85dd47953143aaaad8..038012e23dfcf315fcdee4e604a071f0d30c5902 100644
--- a/src/client_server/media.rs
+++ b/src/client_server/media.rs
@@ -27,7 +27,7 @@ pub fn get_media_config_route(
 )]
 pub fn create_content_route(
     db: State<'_, Database>,
-    body: Ruma<create_content::Request>,
+    body: Ruma<create_content::Request<'_>>,
 ) -> ConduitResult<create_content::Response> {
     let mxc = format!(
         "mxc://{}/{}",
@@ -36,7 +36,7 @@ pub fn create_content_route(
     );
     db.media.create(
         mxc.clone(),
-        body.filename.as_ref(),
+        &body.filename,
         &body.content_type,
         &body.file,
     )?;
@@ -53,7 +53,7 @@ pub fn create_content_route(
 )]
 pub fn get_content_route(
     db: State<'_, Database>,
-    body: Ruma<get_content::IncomingRequest>,
+    body: Ruma<get_content::Request<'_>>,
     _server_name: String,
     _media_id: String,
 ) -> ConduitResult<get_content::Response> {
@@ -85,7 +85,7 @@ pub fn get_content_route(
 )]
 pub fn get_content_thumbnail_route(
     db: State<'_, Database>,
-    body: Ruma<get_content_thumbnail::IncomingRequest>,
+    body: Ruma<get_content_thumbnail::Request<'_>>,
     _server_name: String,
     _media_id: String,
 ) -> ConduitResult<get_content_thumbnail::Response> {
diff --git a/src/client_server/membership.rs b/src/client_server/membership.rs
index 6d1931bf1bb0d7502c5c265118f11c948bd5ab82..606e4700af8b53e10046bf8a7971c1f10caea728 100644
--- a/src/client_server/membership.rs
+++ b/src/client_server/membership.rs
@@ -32,7 +32,7 @@
 )]
 pub async fn join_room_by_id_route(
     db: State<'_, Database>,
-    body: Ruma<join_room_by_id::IncomingRequest>,
+    body: Ruma<join_room_by_id::Request<'_>>,
 ) -> ConduitResult<join_room_by_id::Response> {
     join_room_by_id_helper(
         &db,
@@ -49,7 +49,7 @@ pub async fn join_room_by_id_route(
 )]
 pub async fn join_room_by_id_or_alias_route(
     db: State<'_, Database>,
-    body: Ruma<join_room_by_id_or_alias::IncomingRequest>,
+    body: Ruma<join_room_by_id_or_alias::Request<'_>>,
 ) -> ConduitResult<join_room_by_id_or_alias::Response> {
     let room_id = match RoomId::try_from(body.room_id_or_alias.clone()) {
         Ok(room_id) => room_id,
@@ -81,7 +81,7 @@ pub async fn join_room_by_id_or_alias_route(
 )]
 pub fn leave_room_route(
     db: State<'_, Database>,
-    body: Ruma<leave_room::IncomingRequest>,
+    body: Ruma<leave_room::Request<'_>>,
 ) -> ConduitResult<leave_room::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -127,11 +127,11 @@ pub fn leave_room_route(
 )]
 pub fn invite_user_route(
     db: State<'_, Database>,
-    body: Ruma<invite_user::Request>,
+    body: Ruma<invite_user::Request<'_>>,
 ) -> ConduitResult<invite_user::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
-    if let invite_user::InvitationRecipient::UserId { user_id } = &body.recipient {
+    if let invite_user::IncomingInvitationRecipient::UserId { user_id } = &body.recipient {
         db.rooms.build_and_append_pdu(
             PduBuilder {
                 room_id: body.room_id.clone(),
@@ -165,7 +165,7 @@ pub fn invite_user_route(
 )]
 pub fn kick_user_route(
     db: State<'_, Database>,
-    body: Ruma<kick_user::IncomingRequest>,
+    body: Ruma<kick_user::Request<'_>>,
 ) -> ConduitResult<kick_user::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -212,7 +212,7 @@ pub fn kick_user_route(
 )]
 pub fn ban_user_route(
     db: State<'_, Database>,
-    body: Ruma<ban_user::IncomingRequest>,
+    body: Ruma<ban_user::Request<'_>>,
 ) -> ConduitResult<ban_user::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -267,7 +267,7 @@ pub fn ban_user_route(
 )]
 pub fn unban_user_route(
     db: State<'_, Database>,
-    body: Ruma<unban_user::IncomingRequest>,
+    body: Ruma<unban_user::Request<'_>>,
 ) -> ConduitResult<unban_user::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -313,7 +313,7 @@ pub fn unban_user_route(
 )]
 pub fn forget_room_route(
     db: State<'_, Database>,
-    body: Ruma<forget_room::IncomingRequest>,
+    body: Ruma<forget_room::Request<'_>>,
 ) -> ConduitResult<forget_room::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -348,7 +348,7 @@ pub fn joined_rooms_route(
 )]
 pub fn get_member_events_route(
     db: State<'_, Database>,
-    body: Ruma<get_member_events::Request>,
+    body: Ruma<get_member_events::Request<'_>>,
 ) -> ConduitResult<get_member_events::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -376,7 +376,7 @@ pub fn get_member_events_route(
 )]
 pub fn joined_members_route(
     db: State<'_, Database>,
-    body: Ruma<joined_members::Request>,
+    body: Ruma<joined_members::Request<'_>>,
 ) -> ConduitResult<joined_members::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -422,9 +422,9 @@ async fn join_room_by_id_helper(
             &db,
             room_id.server_name().to_string(),
             federation::membership::create_join_event_template::v1::Request {
-                room_id: room_id.clone(),
-                user_id: sender_id.clone(),
-                ver: vec![RoomVersionId::Version5, RoomVersionId::Version6],
+                room_id,
+                user_id: sender_id,
+                ver: &[RoomVersionId::Version5, RoomVersionId::Version6],
             },
         )
         .await?;
@@ -474,8 +474,8 @@ async fn join_room_by_id_helper(
             &db,
             room_id.server_name().to_string(),
             federation::membership::create_join_event::v1::Request {
-                room_id: room_id.clone(),
-                event_id,
+                room_id,
+                event_id: &event_id,
                 pdu_stub: serde_json::from_value(join_event_stub_value)
                     .expect("we just created this event"),
             },
diff --git a/src/client_server/message.rs b/src/client_server/message.rs
index 03832d86fdd4e8e117423ccb942849fee147dbda..09c3517fae311ddd01dd0185f9ae7a3d9c6b9945 100644
--- a/src/client_server/message.rs
+++ b/src/client_server/message.rs
@@ -18,7 +18,7 @@
 )]
 pub fn send_message_event_route(
     db: State<'_, Database>,
-    body: Ruma<send_message_event::IncomingRequest>,
+    body: Ruma<send_message_event::Request<'_>>,
 ) -> ConduitResult<send_message_event::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -53,7 +53,7 @@ pub fn send_message_event_route(
 )]
 pub fn get_message_events_route(
     db: State<'_, Database>,
-    body: Ruma<get_message_events::IncomingRequest>,
+    body: Ruma<get_message_events::Request<'_>>,
 ) -> ConduitResult<get_message_events::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -96,7 +96,7 @@ pub fn get_message_events_route(
                 .collect::<Vec<_>>();
 
             let mut resp = get_message_events::Response::new();
-            resp.start = Some(body.from.clone());
+            resp.start = Some(body.from.to_owned());
             resp.end = end_token;
             resp.chunk = events_after;
             resp.state = Vec::new();
@@ -120,7 +120,7 @@ pub fn get_message_events_route(
                 .collect::<Vec<_>>();
 
             let mut resp = get_message_events::Response::new();
-            resp.start = Some(body.from.clone());
+            resp.start = Some(body.from.to_owned());
             resp.end = start_token;
             resp.chunk = events_before;
             resp.state = Vec::new();
diff --git a/src/client_server/presence.rs b/src/client_server/presence.rs
index 0b6a51f4e7bd812d012ff83517063a00fcdf9b1d..d105eb6ab3168aee5fee9ed9c10d24320c77cc43 100644
--- a/src/client_server/presence.rs
+++ b/src/client_server/presence.rs
@@ -12,7 +12,7 @@
 )]
 pub fn set_presence_route(
     db: State<'_, Database>,
-    body: Ruma<set_presence::Request>,
+    body: Ruma<set_presence::Request<'_>>,
 ) -> ConduitResult<set_presence::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/profile.rs b/src/client_server/profile.rs
index 0707b342dfe5ce668f914f95f4fff37d8e2830de..386d8988548d4bd95fc72d7c5a272a7ec6445067 100644
--- a/src/client_server/profile.rs
+++ b/src/client_server/profile.rs
@@ -21,7 +21,7 @@
 )]
 pub fn set_displayname_route(
     db: State<'_, Database>,
-    body: Ruma<set_display_name::Request>,
+    body: Ruma<set_display_name::Request<'_>>,
 ) -> ConduitResult<set_display_name::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -98,7 +98,7 @@ pub fn set_displayname_route(
 )]
 pub fn get_displayname_route(
     db: State<'_, Database>,
-    body: Ruma<get_display_name::Request>,
+    body: Ruma<get_display_name::Request<'_>>,
 ) -> ConduitResult<get_display_name::Response> {
     Ok(get_display_name::Response {
         displayname: db.users.displayname(&body.user_id)?,
@@ -112,7 +112,7 @@ pub fn get_displayname_route(
 )]
 pub fn set_avatar_url_route(
     db: State<'_, Database>,
-    body: Ruma<set_avatar_url::Request>,
+    body: Ruma<set_avatar_url::Request<'_>>,
 ) -> ConduitResult<set_avatar_url::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -201,7 +201,7 @@ pub fn set_avatar_url_route(
 )]
 pub fn get_avatar_url_route(
     db: State<'_, Database>,
-    body: Ruma<get_avatar_url::Request>,
+    body: Ruma<get_avatar_url::Request<'_>>,
 ) -> ConduitResult<get_avatar_url::Response> {
     Ok(get_avatar_url::Response {
         avatar_url: db.users.avatar_url(&body.user_id)?,
@@ -215,7 +215,7 @@ pub fn get_avatar_url_route(
 )]
 pub fn get_profile_route(
     db: State<'_, Database>,
-    body: Ruma<get_profile::Request>,
+    body: Ruma<get_profile::Request<'_>>,
 ) -> ConduitResult<get_profile::Response> {
     let avatar_url = db.users.avatar_url(&body.user_id)?;
     let displayname = db.users.displayname(&body.user_id)?;
diff --git a/src/client_server/read_marker.rs b/src/client_server/read_marker.rs
index ff72765f3471a4dcfaa075a0f0e84af83458adb6..023eece2b2050ff06a4edb782923d967c8d0945d 100644
--- a/src/client_server/read_marker.rs
+++ b/src/client_server/read_marker.rs
@@ -15,7 +15,7 @@
 )]
 pub fn set_read_marker_route(
     db: State<'_, Database>,
-    body: Ruma<set_read_marker::Request>,
+    body: Ruma<set_read_marker::Request<'_>>,
 ) -> ConduitResult<set_read_marker::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -52,7 +52,7 @@ pub fn set_read_marker_route(
         );
         let mut receipt_content = BTreeMap::new();
         receipt_content.insert(
-            event.clone(),
+            event.to_owned(),
             ruma::events::receipt::Receipts {
                 read: Some(user_receipts),
             },
diff --git a/src/client_server/redact.rs b/src/client_server/redact.rs
index 8708692f313fa2f753acfa0df8871b1205383c06..cd1b44384a185e2b3dda846143f9cb01f9f984c4 100644
--- a/src/client_server/redact.rs
+++ b/src/client_server/redact.rs
@@ -14,7 +14,7 @@
 )]
 pub fn redact_event_route(
     db: State<'_, Database>,
-    body: Ruma<redact_event::Request>,
+    body: Ruma<redact_event::Request<'_>>,
 ) -> ConduitResult<redact_event::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/room.rs b/src/client_server/room.rs
index 3ee21b6d86f60ce937bc65b9c0d4018a72dede8d..9918123f8d4813192283725a05cda565f3eb0d8d 100644
--- a/src/client_server/room.rs
+++ b/src/client_server/room.rs
@@ -22,7 +22,7 @@
 )]
 pub fn create_room_route(
     db: State<'_, Database>,
-    body: Ruma<create_room::Request>,
+    body: Ruma<create_room::Request<'_>>,
 ) -> ConduitResult<create_room::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -48,11 +48,8 @@ pub fn create_room_route(
         })?;
 
     let mut content = ruma::events::room::create::CreateEventContent::new(sender_id.clone());
-    content.federate = body.creation_content.as_ref().map_or(true, |c| c.federate);
-    content.predecessor = body
-        .creation_content
-        .as_ref()
-        .and_then(|c| c.predecessor.clone());
+    content.federate = body.creation_content.federate;
+    content.predecessor = body.creation_content.predecessor.clone();
     content.room_version = RoomVersionId::Version6;
 
     // 1. The room create event
@@ -80,7 +77,7 @@ pub fn create_room_route(
                 membership: member::MembershipState::Join,
                 displayname: db.users.displayname(&sender_id)?,
                 avatar_url: db.users.avatar_url(&sender_id)?,
-                is_direct: body.is_direct,
+                is_direct: Some(body.is_direct),
                 third_party_invite: None,
             })
             .expect("event is valid, we just created it"),
@@ -137,8 +134,7 @@ pub fn create_room_route(
     // 4. Events set by preset
 
     // Figure out preset. We need it for preset specific events
-    let visibility = body.visibility.unwrap_or(room::Visibility::Private);
-    let preset = body.preset.unwrap_or_else(|| match visibility {
+    let preset = body.preset.unwrap_or_else(|| match body.visibility {
         room::Visibility::Private => create_room::RoomPreset::PrivateChat,
         room::Visibility::Public => create_room::RoomPreset::PublicChat,
     });
@@ -213,32 +209,19 @@ pub fn create_room_route(
     )?;
 
     // 5. Events listed in initial_state
-    for create_room::InitialStateEvent {
-        event_type,
-        state_key,
-        content,
-    } in &body.initial_state
-    {
+    for event in &body.initial_state {
+        let pdu_builder = serde_json::from_str::<PduBuilder>(
+            &serde_json::to_string(&event).expect("AnyInitialStateEvent::to_string always works"),
+        ).map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid initial state event."))?;
+
         // Silently skip encryption events if they are not allowed
-        if event_type == &EventType::RoomEncryption && db.globals.encryption_disabled() {
+        if pdu_builder.event_type == EventType::RoomEncryption && db.globals.encryption_disabled()
+        {
             continue;
         }
 
-        db.rooms.build_and_append_pdu(
-            PduBuilder {
-                room_id: room_id.clone(),
-                sender: sender_id.clone(),
-                event_type: event_type.clone(),
-                content: serde_json::from_str(content.get()).map_err(|_| {
-                    Error::BadRequest(ErrorKind::BadJson, "Invalid initial_state content.")
-                })?,
-                unsigned: None,
-                state_key: state_key.clone(),
-                redacts: None,
-            },
-            &db.globals,
-            &db.account_data,
-        )?;
+        db.rooms
+            .build_and_append_pdu(pdu_builder, &db.globals, &db.account_data)?;
     }
 
     // 6. Events implied by name and topic
@@ -293,7 +276,7 @@ pub fn create_room_route(
                     membership: member::MembershipState::Invite,
                     displayname: db.users.displayname(&user)?,
                     avatar_url: db.users.avatar_url(&user)?,
-                    is_direct: body.is_direct,
+                    is_direct: Some(body.is_direct),
                     third_party_invite: None,
                 })
                 .expect("event is valid, we just created it"),
@@ -311,7 +294,7 @@ pub fn create_room_route(
         db.rooms.set_alias(&alias, Some(&room_id), &db.globals)?;
     }
 
-    if let Some(room::Visibility::Public) = body.visibility {
+    if body.visibility == room::Visibility::Public {
         db.rooms.set_public(&room_id, true)?;
     }
 
@@ -324,7 +307,7 @@ pub fn create_room_route(
 )]
 pub fn get_room_event_route(
     db: State<'_, Database>,
-    body: Ruma<get_room_event::Request>,
+    body: Ruma<get_room_event::Request<'_>>,
 ) -> ConduitResult<get_room_event::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/search.rs b/src/client_server/search.rs
index 082711d130f2272ec330dfb677d21e4841792abf..2967e001e9b080c50510813d6e052a110fd79d90 100644
--- a/src/client_server/search.rs
+++ b/src/client_server/search.rs
@@ -1,11 +1,10 @@
 use super::State;
 use crate::{ConduitResult, Database, Error, Ruma};
-use js_int::uint;
 use ruma::api::client::{error::ErrorKind, r0::search::search_events};
 
 #[cfg(feature = "conduit_bin")]
 use rocket::post;
-use search_events::{ResultCategories, ResultRoomEvents, SearchResult};
+use search_events::{EventContextResult, ResultCategories, ResultRoomEvents, SearchResult};
 use std::collections::BTreeMap;
 
 #[cfg_attr(
@@ -14,7 +13,7 @@
 )]
 pub fn search_events_route(
     db: State<'_, Database>,
-    body: Ruma<search_events::IncomingRequest>,
+    body: Ruma<search_events::Request<'_>>,
 ) -> ConduitResult<search_events::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -51,13 +50,18 @@ pub fn search_events_route(
         .0
         .map(|result| {
             Ok::<_, Error>(SearchResult {
-                context: None,
+                context: EventContextResult {
+                    end: None,
+                    events_after: Vec::new(),
+                    events_before: Vec::new(),
+                    profile_info: BTreeMap::new(),
+                    start: None,
+                },
                 rank: None,
                 result: db
                     .rooms
                     .get_pdu_from_id(&result)?
-                    // TODO this is an awkward type conversion see method
-                    .map(|pdu| pdu.to_any_event()),
+                    .map(|pdu| pdu.to_room_event()),
             })
         })
         .filter_map(|r| r.ok())
@@ -72,14 +76,14 @@ pub fn search_events_route(
     };
 
     Ok(search_events::Response::new(ResultCategories {
-        room_events: Some(ResultRoomEvents {
-            count: uint!(0),         // TODO
+        room_events: ResultRoomEvents {
+            count: None, // TODO? maybe not
             groups: BTreeMap::new(), // TODO
             next_batch,
             results,
             state: BTreeMap::new(), // TODO
             highlights: search.1,
-        }),
+        },
     })
     .into())
 }
diff --git a/src/client_server/session.rs b/src/client_server/session.rs
index 948b455b751260d718fd1fc7b00f4c13c30eea39..9cd051ce1e85b2181b336b531828230a5aa3a395 100644
--- a/src/client_server/session.rs
+++ b/src/client_server/session.rs
@@ -36,7 +36,7 @@ pub fn get_login_types_route() -> ConduitResult<get_login_types::Response> {
 )]
 pub fn login_route(
     db: State<'_, Database>,
-    body: Ruma<login::IncomingRequest>,
+    body: Ruma<login::Request<'_>>,
 ) -> ConduitResult<login::Response> {
     // Validate login method
     let user_id =
diff --git a/src/client_server/state.rs b/src/client_server/state.rs
index e7d2bcf3e9361a1d610f56ab53bebd2e150afb29..75463cbac008caf9d3e28bb953438fad8c629d45 100644
--- a/src/client_server/state.rs
+++ b/src/client_server/state.rs
@@ -21,7 +21,7 @@
 )]
 pub fn send_state_event_for_key_route(
     db: State<'_, Database>,
-    body: Ruma<send_state_event_for_key::IncomingRequest>,
+    body: Ruma<send_state_event_for_key::Request<'_>>,
 ) -> ConduitResult<send_state_event_for_key::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -40,7 +40,7 @@ pub fn send_state_event_for_key_route(
             &body.content,
             content,
             &body.room_id,
-            Some(body.state_key.clone()),
+            Some(body.state_key.to_owned()),
         )?)
         .into(),
     )
@@ -52,7 +52,7 @@ pub fn send_state_event_for_key_route(
 )]
 pub fn send_state_event_for_empty_key_route(
     db: State<'_, Database>,
-    body: Ruma<send_state_event_for_empty_key::IncomingRequest>,
+    body: Ruma<send_state_event_for_empty_key::Request<'_>>,
 ) -> ConduitResult<send_state_event_for_empty_key::Response> {
     // This just calls send_state_event_for_key_route
     let Ruma {
diff --git a/src/client_server/sync.rs b/src/client_server/sync.rs
index 74329605e1c30a5f97a050cc01435f76cb39f66a..167ee75ef22329ca2a10914521d85ace6a950f3c 100644
--- a/src/client_server/sync.rs
+++ b/src/client_server/sync.rs
@@ -31,7 +31,7 @@
 )]
 pub async fn sync_events_route(
     db: State<'_, Database>,
-    body: Ruma<sync_events::IncomingRequest>,
+    body: Ruma<sync_events::Request<'_>>,
 ) -> ConduitResult<sync_events::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
     let device_id = body.device_id.as_ref().expect("user is authenticated");
diff --git a/src/client_server/tag.rs b/src/client_server/tag.rs
index 99ee6e349dbf91e476c6f0f737f63dacaed36a94..d04dd3aebf86e31de1a55efe2464f24c73d3c1f3 100644
--- a/src/client_server/tag.rs
+++ b/src/client_server/tag.rs
@@ -15,7 +15,7 @@
 )]
 pub fn update_tag_route(
     db: State<'_, Database>,
-    body: Ruma<create_tag::Request>,
+    body: Ruma<create_tag::Request<'_>>,
 ) -> ConduitResult<create_tag::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -49,7 +49,7 @@ pub fn update_tag_route(
 )]
 pub fn delete_tag_route(
     db: State<'_, Database>,
-    body: Ruma<delete_tag::Request>,
+    body: Ruma<delete_tag::Request<'_>>,
 ) -> ConduitResult<delete_tag::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
@@ -80,7 +80,7 @@ pub fn delete_tag_route(
 )]
 pub fn get_tags_route(
     db: State<'_, Database>,
-    body: Ruma<get_tags::Request>,
+    body: Ruma<get_tags::Request<'_>>,
 ) -> ConduitResult<get_tags::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/to_device.rs b/src/client_server/to_device.rs
index ca423fefda5b9d7d6a4305ac19982d78ca7bd82e..fe741011146358af80c345c39dbc13061cf7acd6 100644
--- a/src/client_server/to_device.rs
+++ b/src/client_server/to_device.rs
@@ -14,7 +14,7 @@
 )]
 pub fn send_event_to_device_route(
     db: State<'_, Database>,
-    body: Ruma<send_event_to_device::IncomingRequest>,
+    body: Ruma<send_event_to_device::Request<'_>>,
 ) -> ConduitResult<send_event_to_device::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
diff --git a/src/client_server/typing.rs b/src/client_server/typing.rs
index 7eba13e170f2d42bde372bdf684ff7f379018ded..b15121c02876b3d5c5a4a46f02247e8f11320e19 100644
--- a/src/client_server/typing.rs
+++ b/src/client_server/typing.rs
@@ -1,5 +1,6 @@
 use super::State;
 use crate::{utils, ConduitResult, Database, Ruma};
+use create_typing_event::Typing;
 use ruma::api::client::r0::typing::create_typing_event;
 
 #[cfg(feature = "conduit_bin")]
@@ -11,16 +12,15 @@
 )]
 pub fn create_typing_event_route(
     db: State<'_, Database>,
-    body: Ruma<create_typing_event::Request>,
+    body: Ruma<create_typing_event::Request<'_>>,
 ) -> ConduitResult<create_typing_event::Response> {
     let sender_id = body.sender_id.as_ref().expect("user is authenticated");
 
-    if body.typing {
+    if let Typing::Yes(duration) = body.state {
         db.rooms.edus.roomactive_add(
             &sender_id,
             &body.room_id,
-            body.timeout.map(|d| d.as_millis() as u64).unwrap_or(30000)
-                + utils::millis_since_unix_epoch(),
+            duration.as_millis() as u64 + utils::millis_since_unix_epoch(),
             &db.globals,
         )?;
     } else {
diff --git a/src/client_server/user_directory.rs b/src/client_server/user_directory.rs
index f47643c1a7170604be730d017c6bdd6172880753..dcf48fe3c7862e570e0b3f8b03ce3696ebc508e5 100644
--- a/src/client_server/user_directory.rs
+++ b/src/client_server/user_directory.rs
@@ -11,7 +11,7 @@
 )]
 pub fn search_users_route(
     db: State<'_, Database>,
-    body: Ruma<search_users::IncomingRequest>,
+    body: Ruma<search_users::Request<'_>>,
 ) -> ConduitResult<search_users::Response> {
     let limit = u64::from(body.limit) as usize;
 
diff --git a/src/database/media.rs b/src/database/media.rs
index e9dcb4a00a5ea42faa1480e90dd10d6608f30ff1..63fa11c64ed85d5177c33d22ea72e78ab9431a03 100644
--- a/src/database/media.rs
+++ b/src/database/media.rs
@@ -16,7 +16,7 @@ impl Media {
     pub fn create(
         &self,
         mxc: String,
-        filename: Option<&String>,
+        filename: &Option<String>,
         content_type: &str,
         file: &[u8],
     ) -> Result<()> {
@@ -25,7 +25,7 @@ pub fn create(
         key.extend_from_slice(&0_u32.to_be_bytes()); // Width = 0 if it's not a thumbnail
         key.extend_from_slice(&0_u32.to_be_bytes()); // Height = 0 if it's not a thumbnail
         key.push(0xff);
-        key.extend_from_slice(filename.map(|f| f.as_bytes()).unwrap_or_default());
+        key.extend_from_slice(filename.as_ref().map(|f| f.as_bytes()).unwrap_or_default());
         key.push(0xff);
         key.extend_from_slice(content_type.as_bytes());
 
diff --git a/src/database/users.rs b/src/database/users.rs
index 1b6a6812e877a049b4ac591daba3b8bc2f747f85..10e1ef301533b0e306feff9d2aba1f60bb2ba790 100644
--- a/src/database/users.rs
+++ b/src/database/users.rs
@@ -8,7 +8,7 @@
             keys::{CrossSigningKey, OneTimeKey},
         },
     },
-    encryption::DeviceKeys,
+    encryption::IncomingDeviceKeys,
     events::{AnyToDeviceEvent, EventType},
     DeviceId, DeviceKeyAlgorithm, DeviceKeyId, Raw, UserId,
 };
@@ -395,7 +395,7 @@ pub fn add_device_keys(
         &self,
         user_id: &UserId,
         device_id: &DeviceId,
-        device_keys: &DeviceKeys,
+        device_keys: &IncomingDeviceKeys,
         rooms: &super::rooms::Rooms,
         globals: &super::globals::Globals,
     ) -> Result<()> {
@@ -625,7 +625,7 @@ pub fn get_device_keys(
         &self,
         user_id: &UserId,
         device_id: &DeviceId,
-    ) -> Result<Option<DeviceKeys>> {
+    ) -> Result<Option<IncomingDeviceKeys>> {
         let mut key = user_id.to_string().as_bytes().to_vec();
         key.push(0xff);
         key.extend_from_slice(device_id.as_bytes());
diff --git a/src/error.rs b/src/error.rs
index 623aa0ef94f873d3b9749104a9b7becb553fa142..f521da43de37a02a2694c1d4427b8c957efafd87 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -70,14 +70,14 @@ fn respond_to(self, r: &'r Request<'_>) -> response::Result<'o> {
         use ErrorKind::*;
         let (kind, status_code) = match self {
             Self::BadRequest(kind, _) => (
-                kind,
+                kind.clone(),
                 match kind {
                     Forbidden | GuestAccessForbidden | ThreepidAuthFailed | ThreepidDenied => {
                         StatusCode::FORBIDDEN
                     }
-                    Unauthorized | UnknownToken | MissingToken => StatusCode::UNAUTHORIZED,
+                    Unauthorized | UnknownToken { .. } | MissingToken => StatusCode::UNAUTHORIZED,
                     NotFound => StatusCode::NOT_FOUND,
-                    LimitExceeded => StatusCode::TOO_MANY_REQUESTS,
+                    LimitExceeded { .. } => StatusCode::TOO_MANY_REQUESTS,
                     UserDeactivated => StatusCode::FORBIDDEN,
                     TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
                     _ => StatusCode::BAD_REQUEST,
diff --git a/src/pdu.rs b/src/pdu.rs
index b565a24c61902fac9934fcff3c5edbf34c040c2c..152648423883fa7bbadb24cad9eea89498568a94 100644
--- a/src/pdu.rs
+++ b/src/pdu.rs
@@ -255,7 +255,7 @@ pub fn convert_for_state_res(&self) -> Result<state_res::StateEvent> {
 }
 
 /// Build the start of a PDU in order to add it to the `Database`.
-#[derive(Debug)]
+#[derive(Debug, Deserialize)]
 pub struct PduBuilder {
     pub room_id: RoomId,
     pub sender: UserId,
diff --git a/src/ruma_wrapper.rs b/src/ruma_wrapper.rs
index 80e6e5829156e204254fc8d787cec79e081701ba..734d2144ce78c494afa94535b4e03ec2f784e43d 100644
--- a/src/ruma_wrapper.rs
+++ b/src/ruma_wrapper.rs
@@ -1,9 +1,9 @@
 use crate::Error;
 use ruma::{
-    api::IncomingRequest,
+    api::{Outgoing, OutgoingRequest},
     identifiers::{DeviceId, UserId},
 };
-use std::{convert::TryInto, ops::Deref};
+use std::{convert::TryFrom, convert::TryInto, ops::Deref};
 
 #[cfg(feature = "conduit_bin")]
 use {
@@ -24,15 +24,21 @@
 
 /// This struct converts rocket requests into ruma structs by converting them into http requests
 /// first.
-pub struct Ruma<T: IncomingRequest> {
-    pub body: T,
+pub struct Ruma<T: Outgoing> {
+    pub body: T::Incoming,
     pub sender_id: Option<UserId>,
     pub device_id: Option<Box<DeviceId>>,
     pub json_body: Option<Box<serde_json::value::RawValue>>, // This is None when body is not a valid string
 }
 
 #[cfg(feature = "conduit_bin")]
-impl<'a, T: IncomingRequest> FromTransformedData<'a> for Ruma<T> {
+impl<'a, T: Outgoing + OutgoingRequest> FromTransformedData<'a> for Ruma<T>
+where
+    <T as Outgoing>::Incoming: TryFrom<http::request::Request<std::vec::Vec<u8>>> + std::fmt::Debug,
+    <<T as Outgoing>::Incoming as std::convert::TryFrom<
+        http::request::Request<std::vec::Vec<u8>>,
+    >>::Error: std::fmt::Debug,
+{
     type Error = (); // TODO: Better error handling
     type Owned = Data;
     type Borrowed = Self::Owned;
@@ -93,7 +99,7 @@ fn from_data(
             let http_request = http_request.body(body.clone()).unwrap();
             log::info!("{:?}", http_request);
 
-            match T::try_from(http_request) {
+            match <T as Outgoing>::Incoming::try_from(http_request) {
                 Ok(t) => Success(Ruma {
                     body: t,
                     sender_id: user_id,
@@ -112,8 +118,8 @@ fn from_data(
     }
 }
 
-impl<T: IncomingRequest> Deref for Ruma<T> {
-    type Target = T;
+impl<T: Outgoing> Deref for Ruma<T> {
+    type Target = T::Incoming;
 
     fn deref(&self) -> &Self::Target {
         &self.body
diff --git a/src/server_server.rs b/src/server_server.rs
index ac4407baa6a2ad92bf8f6924206d266df78e9ab7..d39abe6451f25d368f1b66bd300a8fc62d498b4a 100644
--- a/src/server_server.rs
+++ b/src/server_server.rs
@@ -207,7 +207,7 @@ pub fn get_server_keys_deprecated(db: State<'_, Database>) -> Json<String> {
 )]
 pub async fn get_public_rooms_route(
     db: State<'_, Database>,
-    body: Ruma<get_public_rooms::v1::IncomingRequest>,
+    body: Ruma<get_public_rooms::v1::Request<'_>>,
 ) -> ConduitResult<get_public_rooms::v1::Response> {
     let Ruma {
         body:
@@ -230,7 +230,7 @@ pub async fn get_public_rooms_route(
         limit,
         since.as_deref(),
         None,
-        Some(ruma::directory::RoomNetwork::Matrix),
+        Some(ruma::directory::IncomingRoomNetwork::Matrix),
     )
     .await?
     .0;
@@ -264,7 +264,7 @@ pub async fn get_public_rooms_route(
 )]
 pub fn send_transaction_message_route<'a>(
     _db: State<'a, Database>,
-    body: Ruma<send_transaction_message::v1::IncomingRequest>,
+    body: Ruma<send_transaction_message::v1::Request<'_>>,
 ) -> ConduitResult<send_transaction_message::v1::Response> {
     dbg!(&*body);
     Ok(send_transaction_message::v1::Response {