diff --git a/src/rust/kurisu_api/src/route.rs b/src/rust/kurisu_api/src/route.rs
index 51e88355ed2e56b5eb521ba27cf357860be616b1..c497855d685896c49691c75553bb5da5140f5ea8 100644
--- a/src/rust/kurisu_api/src/route.rs
+++ b/src/rust/kurisu_api/src/route.rs
@@ -45,7 +45,7 @@ macro_rules! route {
 #[macro_export]
 macro_rules! new_route {
     ($obj:ident :: $route:literal # $args:literal -> $ret:ident) => {
-        struct $obj;
+        pub struct $obj;
         impl $crate::route::ApiRoute<$args> for $obj {
             const ROUTE: &'static str = $route;
             type Object<'de> = $ret<'de>;
@@ -55,23 +55,18 @@ macro_rules! new_route {
 
 #[cfg(test)]
 mod test {
-    use crate::v2::*;
-
     #[test]
     fn simple_example() {
-        new_route! { GetRepo     :: "/"           #0 -> Repo      };
-        new_route! { GetKara     :: "/kara/@"     #1 -> Kara      };
-        new_route! { GetPlaylist :: "/playlist/@" #1 -> Playlist  };
-
+        use crate::v2::*;
         assert_eq!(route!(GetKara -> 1), "/kara/1");
     }
 
     #[test]
     fn invalid_route() {
-        new_route! { GetKara::"/kara/@/@"#1 -> Kara };
-
+        use crate::v2::*;
         // Note that no error is returned, because we don't check the route
         // creation...
+        new_route! { GetKara :: "/kara/@/@" #1 -> Kara }
         assert_eq!(route!(GetKara -> 1), "/kara/1/@");
     }
 }
diff --git a/src/rust/kurisu_api/src/v2.rs b/src/rust/kurisu_api/src/v2.rs
index a75cddeec3dc6489ce299380139a07840c6a56fc..0ba6f985eb5d5d43b1dea48dfaf5f9dd79e13ea5 100644
--- a/src/rust/kurisu_api/src/v2.rs
+++ b/src/rust/kurisu_api/src/v2.rs
@@ -9,7 +9,7 @@ pub struct Repo<'a> {
     pub trusted: Vec<&'a str>,
     pub song_types: Vec<&'a str>,
     pub song_origins: Vec<&'a str>,
-    pub playlists: Vec<&'a str>,
+    pub last_modified_epoch: i64,
 }
 
 #[derive(Debug, Deserialize, PartialEq, Eq)]
@@ -44,8 +44,6 @@ pub enum SongOrigin {
 
 #[derive(Debug, Deserialize, PartialEq, Eq)]
 pub struct Kara<'a> {
-    pub id: i64,
-
     #[serde(rename = "title")]
     pub song_title: &'a str,
 
@@ -72,16 +70,77 @@ pub struct Kara<'a> {
     pub tags: HashMap<&'a str, Vec<&'a str>>,
 }
 
+#[derive(Debug, Deserialize, PartialEq, Eq)]
+#[serde(transparent)]
+pub struct KaraDl<'a> {
+    pub content: Vec<u8>,
+
+    #[serde(skip)]
+    _phantom: std::marker::PhantomData<&'a u8>,
+}
+
+#[derive(Default, Debug, Deserialize, PartialEq, Eq)]
+#[serde(transparent)]
+pub struct KaraList<'a> {
+    pub content: Vec<i64>,
+
+    #[serde(skip)]
+    _phantom: std::marker::PhantomData<&'a u8>,
+}
+
+#[derive(Default, Debug, Deserialize, PartialEq, Eq)]
+#[serde(transparent)]
+pub struct PlaylistList<'a> {
+    pub content: Vec<i64>,
+
+    #[serde(skip)]
+    _phantom: std::marker::PhantomData<&'a u8>,
+}
+
+new_route! { GetRepo         :: "/"           #0 -> Repo          }
+
+new_route! { GetKaras        :: "/kara"       #0 -> KaraList      }
+new_route! { GetKara         :: "/kara/@"     #1 -> Kara          }
+new_route! { GetKaraDl       :: "/kara/dl/@"  #1 -> KaraDl        }
+
+new_route! { GetPlaylistList :: "/playlist"   #0 -> PlaylistList  }
+new_route! { GetPlaylist     :: "/playlist/@" #1 -> Playlist      }
+
 #[cfg(test)]
 mod test {
     use super::*;
     use commons::{assert_err, assert_ok};
 
+    #[test]
+    fn lists() {
+        assert_eq!(
+            assert_ok!(serde_json::from_str::<KaraList>(r#"[]"#)),
+            Default::default()
+        );
+        assert_eq!(
+            assert_ok!(serde_json::from_str::<PlaylistList>(r#"[]"#)),
+            Default::default()
+        );
+        assert_eq!(
+            assert_ok!(serde_json::from_str::<KaraList>(r#"[ 1, 2, 69 ]"#)),
+            KaraList {
+                content: vec![1, 2, 69],
+                ..Default::default()
+            }
+        );
+        assert_eq!(
+            assert_ok!(serde_json::from_str::<PlaylistList>(r#"[ 0, 42 ]"#)),
+            PlaylistList {
+                content: vec![0, 42],
+                ..Default::default()
+            }
+        );
+    }
+
     #[test]
     fn invalid_karas() {
         assert_err!(serde_json::from_str::<Kara>(
-            r#"{ "id": 001
-               , "title": "Totoro"
+            r#"{ "title": "Totoro"
                , "source": "Totoro"
                , "karamakers": [ "Viieux", "Totoro" ]
                , "is_virtual": false
@@ -135,8 +194,7 @@ mod test {
     #[test]
     fn simple_kara() {
         assert_ok!(serde_json::from_str::<Kara>(
-            r#"{ "id": 1
-               , "title": "Totoro"
+            r#"{ "title": "Totoro"
                , "source": "Totoro"
                , "karamakers": [ "Viieux", "Totoro" ]
                , "is_virtual": false
@@ -152,8 +210,7 @@ mod test {
     #[test]
     fn tagged_kara() {
         let Kara { tags, .. } = assert_ok!(serde_json::from_str::<Kara>(
-            r#"{ "id": 1
-               , "title": "Totoro"
+            r#"{ "title": "Totoro"
                , "source": "Totoro"
                , "karamakers": [ "Viieux", "Totoro" ]
                , "is_virtual": false