diff --git a/cmake/MatrixStructs.cmake b/cmake/MatrixStructs.cmake
index d57231509341df57641c8dc6cc9ec96dc5ca3e9e..7105dd962968ed56b5ae2cb9c5c9fca1882ccb2d 100644
--- a/cmake/MatrixStructs.cmake
+++ b/cmake/MatrixStructs.cmake
@@ -13,7 +13,7 @@ ExternalProject_Add(
   MatrixStructs
 
   GIT_REPOSITORY https://github.com/mujx/matrix-structs
-  GIT_TAG a84b37215ead77620dcddc0789c4b9b443757a17
+  GIT_TAG 0659554443a98bd018691337c8cfc11bfe909007
 
   BUILD_IN_SOURCE 1
   SOURCE_DIR ${MATRIX_STRUCTS_ROOT}
diff --git a/src/client.cpp b/src/client.cpp
index 6f09b450da1fd581e6329f1d3f44b7e6c74f9bb5..c5023508f547253e1f29cabb3e2a4677b1ee068b 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -306,6 +306,19 @@ Client::leave_room(const mtx::identifiers::Room &room_id,
         post<std::string, nlohmann::json>(api_path, "", callback);
 }
 
+void
+Client::invite_user(const mtx::identifiers::Room &room_id,
+                    const std::string &user_id,
+                    std::function<void(const mtx::responses::RoomInvite &, RequestErr)> callback)
+{
+        mtx::requests::RoomInvite req;
+        req.user_id = user_id;
+
+        auto api_path = "/client/r0/rooms/" + room_id.toString() + "/invite";
+
+        post<mtx::requests::RoomInvite, mtx::responses::RoomInvite>(api_path, req, callback);
+}
+
 void
 Client::sync(const std::string &filter,
              const std::string &since,
diff --git a/src/client.hpp b/src/client.hpp
index baa5a9cb184ee737cc022244a0b17a1cbb274896..21103450556230303e11afddaf45c122469e453f 100644
--- a/src/client.hpp
+++ b/src/client.hpp
@@ -67,7 +67,10 @@ public:
         void leave_room(const mtx::identifiers::Room &room_id,
                         std::function<void(const nlohmann::json &res, RequestErr err)>);
         //! Invite a user to a room.
-        /* void invite_user(); */
+        void invite_user(
+          const mtx::identifiers::Room &room_id,
+          const std::string &user_id,
+          std::function<void(const mtx::responses::RoomInvite &res, RequestErr err)>);
         //! Perform sync.
         void sync(const std::string &filter,
                   const std::string &since,
diff --git a/tests/client_api.cpp b/tests/client_api.cpp
index c4854bb90ec919d40afd4186c0b01632d33e297f..062c02429e6da6618da2106790c9f7d226516480 100644
--- a/tests/client_api.cpp
+++ b/tests/client_api.cpp
@@ -385,6 +385,92 @@ TEST(ClientAPI, LeaveRoom)
         bob->close();
 }
 
+TEST(ClientAPI, InviteRoom)
+{
+        auto alice = std::make_shared<Client>("localhost");
+        auto bob   = std::make_shared<Client>("localhost");
+
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+        });
+
+        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+        });
+
+        // Waiting for the previous requests to complete.
+        std::this_thread::sleep_for(std::chrono::seconds(3));
+
+        mtx::requests::CreateRoom req;
+        req.name   = "Name";
+        req.topic  = "Topic";
+        req.invite = {};
+        alice->create_room(req, [alice, bob](const mtx::responses::CreateRoom &res, ErrType err) {
+                ASSERT_FALSE(err);
+                auto room_id = res.room_id;
+
+                alice->invite_user(
+                  room_id,
+                  "@bob:localhost",
+                  [room_id, bob](const mtx::responses::Empty &, ErrType err) {
+                          ASSERT_FALSE(err);
+                          if (err) {
+                                  std::cout << "Received error when inviting user" << std::endl;
+                          }
+
+                          bob->join_room(room_id, [](const nlohmann::json &, ErrType err) {
+                                  ASSERT_FALSE(err);
+                          });
+                  });
+        });
+
+        alice->close();
+        bob->close();
+}
+
+TEST(ClientAPI, InvalidInvite)
+{
+        auto alice = std::make_shared<Client>("localhost");
+        auto bob   = std::make_shared<Client>("localhost");
+
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+        });
+
+        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
+                boost::ignore_unused(res);
+                ASSERT_FALSE(err);
+        });
+
+        // Waiting for the previous requests to complete.
+        std::this_thread::sleep_for(std::chrono::seconds(3));
+
+        mtx::requests::CreateRoom req;
+        req.name   = "Name";
+        req.topic  = "Topic";
+        req.invite = {};
+        alice->create_room(req, [alice, bob](const mtx::responses::CreateRoom &res, ErrType err) {
+                ASSERT_FALSE(err);
+                auto room_id = res.room_id;
+
+                bob->invite_user(room_id,
+                                 "@carl:localhost",
+                                 [room_id, bob](const mtx::responses::Empty &, ErrType err) {
+                                         ASSERT_TRUE(err);
+                                         EXPECT_EQ(
+                                           mtx::errors::to_string(err->matrix_error.errcode),
+                                           "M_FORBIDDEN");
+
+                                 });
+        });
+
+        alice->close();
+        bob->close();
+}
+
 TEST(ClientAPI, Sync)
 {
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");