diff --git a/cmake/MatrixStructs.cmake b/cmake/MatrixStructs.cmake
index 447deecf22216d03ded301ce8863900ae3b3ca84..f73b8648cf2d06a42540d682c042a10c83b35336 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 83be1388e632a43f0570857cb79313c09fb3da0b
+  GIT_TAG da342f3b3ccf4f505459697f3d857274d0704c45
 
   BUILD_IN_SOURCE 1
   SOURCE_DIR ${MATRIX_STRUCTS_ROOT}
diff --git a/src/client.cpp b/src/client.cpp
index 8a930b5af316f2f780018fa3a7c849662610da5c..7700990cc5ead70dad5c8f047768d94c6a007b2f 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -230,6 +230,7 @@ Client::login(
           [this, callback](const mtx::responses::Login &resp,
                            std::experimental::optional<mtx::client::errors::ClientError> err) {
                   if (!err && resp.access_token.size()) {
+                          user_id_      = resp.user_id;
                           access_token_ = resp.access_token;
                   }
                   callback(resp, err);
@@ -258,6 +259,18 @@ Client::logout(
           });
 }
 
+void
+Client::set_displayname(
+  const std::string &displayname,
+  std::function<void(std::experimental::optional<mtx::client::errors::ClientError>)> callback)
+{
+        mtx::requests::DisplayName req;
+        req.displayname = displayname;
+
+        put<mtx::requests::DisplayName>(
+          "/profile/" + user_id_.toString() + "/displayname", req, callback);
+}
+
 void
 Client::create_room(const mtx::requests::CreateRoom &room_options,
                     std::function<void(const mtx::responses::CreateRoom &, RequestErr)> callback)
diff --git a/src/client.hpp b/src/client.hpp
index acb076bf0f22cbe11b52d596ad07c7af0a7592ac..d6ecae08017da3229883be3306f2759893ab8bd3 100644
--- a/src/client.hpp
+++ b/src/client.hpp
@@ -49,6 +49,8 @@ public:
                    std::function<void(const mtx::responses::Login &response, RequestErr err)>);
         //! Perform logout.
         void logout(std::function<void(const mtx::responses::Logout &response, RequestErr err)>);
+        //! Change displayname.
+        void set_displayname(const std::string &displayname, std::function<void(RequestErr err)>);
         //! Create a room with the given options.
         void create_room(
           const mtx::requests::CreateRoom &room_options,
@@ -101,6 +103,20 @@ private:
                              std::experimental::optional<mtx::client::errors::ClientError>)>,
           bool requires_auth = true);
 
+        // put function for the PUT HTTP requests that send responses
+        template<class Request, class Response>
+        void put(const std::string &endpoint,
+                 const Request &req,
+                 std::function<void(const Response &,
+                                    std::experimental::optional<mtx::client::errors::ClientError>)>,
+                 bool requires_auth = true);
+
+        template<class Request>
+        void put(const std::string &endpoint,
+                 const Request &req,
+                 std::function<void(std::experimental::optional<mtx::client::errors::ClientError>)>,
+                 bool requires_auth = true);
+
         template<class Response>
         void get(const std::string &endpoint,
                  std::function<void(const Response &,
@@ -140,6 +156,8 @@ private:
         std::string server_;
         //! The access token that would be used for authentication.
         std::string access_token_;
+        //! The user ID associated with the client.
+        mtx::identifiers::User user_id_;
         //! The token that will be used as the 'since' parameter on the next sync request.
         std::string next_batch_token_;
 };
@@ -177,6 +195,60 @@ mtx::client::Client::post(
         do_request(session);
 }
 
+// put function for the PUT HTTP requests that send responses
+template<class Request, class Response>
+void
+mtx::client::Client::put(
+  const std::string &endpoint,
+  const Request &req,
+  std::function<void(const Response &,
+                     std::experimental::optional<mtx::client::errors::ClientError>)> callback,
+  bool requires_auth)
+{
+        // Serialize request.
+        nlohmann::json j = req;
+
+        using CallbackType = std::function<void(
+          const Response &, std::experimental::optional<mtx::client::errors::ClientError>)>;
+
+        std::shared_ptr<Session> session = create_session<Response, CallbackType>(callback);
+
+        session->request.method(boost::beast::http::verb::put);
+        session->request.target("/_matrix/client/r0" + endpoint);
+        session->request.set(boost::beast::http::field::user_agent, "mtxclient v0.1.0");
+        session->request.set(boost::beast::http::field::content_type, "application/json");
+        session->request.set(boost::beast::http::field::host, session->host);
+        if (requires_auth && !access_token_.empty())
+                session->request.set(boost::beast::http::field::authorization,
+                                     "Bearer " + access_token_);
+        session->request.body() = j.dump();
+        session->request.prepare_payload();
+
+        do_request(session);
+}
+
+// provides PUT functionality for the endpoints which dont respond with a body
+template<class Request>
+void
+mtx::client::Client::put(
+  const std::string &endpoint,
+  const Request &req,
+  std::function<void(std::experimental::optional<mtx::client::errors::ClientError>)> callback,
+  bool requires_auth)
+{
+        // Serialize request.
+        nlohmann::json j = req;
+
+        mtx::client::Client::put<Request, mtx::responses::Empty>(
+          endpoint,
+          req,
+          [callback](const mtx::responses::Empty,
+                     std::experimental::optional<mtx::client::errors::ClientError> err) {
+                  callback(err);
+          },
+          requires_auth);
+}
+
 template<class Response>
 void
 mtx::client::Client::get(
diff --git a/tests/client_api.cpp b/tests/client_api.cpp
index 1b8f913d2a362fa1baff94cec087688c1fcec6c3..b4bd3fa3ba79b7d2ef8e18aa68090efdac4ac7ca 100644
--- a/tests/client_api.cpp
+++ b/tests/client_api.cpp
@@ -82,6 +82,41 @@ TEST(ClientAPI, LoginWrongUsername)
         mtx_client->close();
 }
 
+TEST(ClientAPI, ChangeDisplayName)
+{
+        std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
+
+        mtx_client->login(
+          "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) {
+                  ASSERT_FALSE(err);
+                  validate_login("@alice:localhost", res);
+
+                  // Change the display name to Arthur Dent and verify its success through the lack
+                  // of an error
+                  mtx_client->set_displayname("Arthur Dent",
+                                              [](ErrType err) { ASSERT_FALSE(err); });
+          });
+
+        mtx_client->close();
+}
+
+TEST(ClientAPI, EmptyDisplayName)
+{
+        std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
+
+        mtx_client->login(
+          "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) {
+                  ASSERT_FALSE(err);
+                  validate_login("@alice:localhost", res);
+
+                  // Change the display name to an empty string and verify its success through the
+                  // lack of an error
+                  mtx_client->set_displayname("", [](ErrType err) { ASSERT_FALSE(err); });
+          });
+
+        mtx_client->close();
+}
+
 TEST(ClientAPI, CreateRoom)
 {
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");