diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 49579705b8acdc8faf7d2ac232a6c1dc9faa08fa..cced2f686368c9f34dae1884140d53958a7e267e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -89,10 +89,10 @@ test:
     - echo "FILE_TO_BE_PATCHED=$FILE_TO_BE_PATCHED"
     - sed -e "s|std::unique_ptr<ContextAllocator> context_allocator) {}|std::unique_ptr<ContextAllocator> /*context_allocator*/) {}|" -i $FILE_TO_BE_PATCHED
     - cmake -DCMAKE_BUILD_TYPE=Debug ..
-    - cmake --build .
-    - cmake --build . --target unit_test_coverage
-    - cmake --build . --target cxxcaosdbcli
-    - cmake --build . --target ccaosdbcli
+    - cmake --build . -j
+    - cmake --build . -j --target unit_test_coverage
+    - cmake --build . -j --target cxxcaosdbcli
+    - cmake --build . -j --target ccaosdbcli
 
 # trigger the integration tests
 trigger_inttest:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4d39bda064d6caf53ddfd816cdb398f1eed07de..aa0ef42ba87dcf92bc82690d837609b5e4a12b67 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,8 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 
 * New functions getEnumNameFromValue() and getEnumValueFromName().
-* Extern C now supports datatypes, roles, and importances as enums,
-  and typed property values
+* Extern C now supports the full C++ functionalities.
 
 ### Changed
 
diff --git a/doc/Examples.rst b/doc/Examples.rst
index ea65e02cd421b880d5d748c6774798ac115d0d9a..ddb24e0bdd6fd7a4f4881a8eb163cb63184b0bb8 100644
--- a/doc/Examples.rst
+++ b/doc/Examples.rst
@@ -224,11 +224,11 @@ Up- and Download a file
   const auto &insert_results = insert_transaction->GetResultSet();
   const auto &inserted_file = insert_results.at(0);
 
-  // for the download you need to use the RetrieveAndDownloadFilesById task and
+  // for the download you need to use the RetrieveAndDownloadFileById task and
   // supply the path where the file shall be stored
   test_download_file = fs::path("test_download_file_delete_me.dat");
   auto download_transaction(connection->CreateTransaction());
-  download_transaction->RetrieveAndDownloadFilesById(
+  download_transaction->RetrieveAndDownloadFileById(
       inserted_file.GetId(), test_download_file.string());
   download_transaction->ExecuteAsynchronously();
   download_transaction->WaitForIt().GetCode()
diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index 0fb724a5316e6f615d4236aa24dc44d338fce803..621c6cbd80057c0f97d171f2ffac91e65b77498f 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -279,7 +279,7 @@ public:
    * If the file cannot be downloaded due to unsufficient permissions an error
    * is appended.
    */
-  auto RetrieveAndDownloadFilesById(const std::string &id, const std::string &local_path) noexcept
+  auto RetrieveAndDownloadFileById(const std::string &id, const std::string &local_path) noexcept
     -> StatusCode;
 
   /**
diff --git a/include/ccaosdb.h b/include/ccaosdb.h
index e23e3a72ad58167e060081757e97d84cbfeaa2b8..b06f3ec388d14a2b15b362babd99e3207a7353ef 100644
--- a/include/ccaosdb.h
+++ b/include/ccaosdb.h
@@ -279,6 +279,8 @@ int caosdb_connection_connection_create_transaction(caosdb_connection_connection
 int caosdb_transaction_delete_transaction(caosdb_transaction_transaction *transaction);
 int caosdb_transaction_transaction_retrieve_by_id(caosdb_transaction_transaction *transaction,
                                                   const char *id);
+int caosdb_transaction_transaction_retrieve_and_download_file_by_id(
+  caosdb_transaction_transaction *transaction, const char *id, const char *path);
 int caosdb_transaction_transaction_retrieve_by_ids(caosdb_transaction_transaction *transaction,
                                                    const char *ids[], int length);
 int caosdb_transaction_transaction_query(caosdb_transaction_transaction *transaction,
@@ -307,6 +309,13 @@ int caosdb_transaction_result_set_at(caosdb_transaction_result_set *result_set,
                                      caosdb_entity_entity *entity, int index);
 int caosdb_transaction_result_set_size(caosdb_transaction_result_set *result_set, int *out);
 
+int caosdb_transaction_transaction_insert_entity(caosdb_transaction_transaction *transaction,
+                                                 caosdb_entity_entity *entity);
+int caosdb_transaction_transaction_update_entity(caosdb_transaction_transaction *transaction,
+                                                 caosdb_entity_entity *entity);
+int caosdb_transaction_transaction_delete_by_id(caosdb_transaction_transaction *transaction,
+                                                const char *id);
+
 typedef struct {
   void *wrapped_property;
   bool _deletable = false;
@@ -325,6 +334,7 @@ int caosdb_entity_entity_get_id(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_role(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_name(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_description(caosdb_entity_entity *entity, char **out);
+int caosdb_entity_entity_get_local_path(caosdb_entity_entity *entity, char **out);
 /**
  * Get the name of the entity's datatype, whether it is a reference, and whether it is a list.
  */
@@ -407,6 +417,8 @@ int caosdb_entity_delete_parent(caosdb_entity_parent *out);
 int caosdb_entity_entity_set_role(caosdb_entity_entity *entity, const char *role);
 int caosdb_entity_entity_set_name(caosdb_entity_entity *entity, const char *name);
 int caosdb_entity_entity_set_description(caosdb_entity_entity *entity, const char *description);
+int caosdb_entity_entity_set_local_path(caosdb_entity_entity *entity, const char *name);
+int caosdb_entity_entity_set_file_path(caosdb_entity_entity *entity, const char *name);
 /**
  * Set the entity's datatype by name, and whether it is a reference or a list.
  */
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 5a7cb74683071f42e54f8ad056f37643092bb4ef..58bf54e92554f4660293a869954e9e3482eebdf7 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -172,8 +172,8 @@ auto Transaction::RetrieveById(const std::string &id) noexcept -> StatusCode {
   return this->status.GetCode();
 }
 
-auto Transaction::RetrieveAndDownloadFilesById(const std::string &id,
-                                               const std::string &local_path) noexcept
+auto Transaction::RetrieveAndDownloadFileById(const std::string &id,
+                                              const std::string &local_path) noexcept
   -> StatusCode {
   ASSERT_CAN_ADD_RETRIEVAL
 
diff --git a/src/ccaosdb.cpp b/src/ccaosdb.cpp
index 40a47227c5d146a97583e5068b033896e17b1cfe..d5165c98e64b7084a395a710a5bd1b98019f9edb 100644
--- a/src/ccaosdb.cpp
+++ b/src/ccaosdb.cpp
@@ -75,7 +75,7 @@ extern "C" {
     GENERIC_ERROR,                                                                                 \
     int caosdb_entity_entity_get_##element(caosdb_entity_entity *entity, char **out), {            \
       auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);                                          \
-      char *tmp = (char *)malloc(sizeof(char) * wrapped_entity->GetFunction.length() + 1);         \
+      auto *tmp = (char *)malloc(sizeof(char) * wrapped_entity->GetFunction.length() + 1);         \
       strcpy(tmp, wrapped_entity->GetFunction.c_str());                                            \
       delete[] * out;                                                                              \
       *out = tmp;                                                                                  \
@@ -101,7 +101,7 @@ extern "C" {
     GENERIC_ERROR,                                                                                 \
     int caosdb_entity_property_get_##element(caosdb_entity_property *property, char **out), {      \
       auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);                                    \
-      char *tmp = (char *)malloc(sizeof(char) * wrapped_property->GetFunction.length() + 1);       \
+      auto *tmp = (char *)malloc(sizeof(char) * wrapped_property->GetFunction.length() + 1);       \
       strcpy(tmp, wrapped_property->GetFunction.c_str());                                          \
       delete[] * out;                                                                              \
       *out = tmp;                                                                                  \
@@ -128,7 +128,7 @@ extern "C" {
     GENERIC_ERROR,                                                                                 \
     int caosdb_entity_parent_get_##element(caosdb_entity_parent *parent, char **out), {            \
       auto *wrapped_parent = WRAPPED_PARENT_CAST(parent);                                          \
-      char *tmp = (char *)malloc(sizeof(char) * wrapped_parent->GetFunction.length() + 1);         \
+      auto *tmp = (char *)malloc(sizeof(char) * wrapped_parent->GetFunction.length() + 1);         \
       strcpy(tmp, wrapped_parent->GetFunction.c_str());                                            \
       delete[] * out;                                                                              \
       *out = tmp;                                                                                  \
@@ -338,12 +338,12 @@ ERROR_RETURN_CODE(
     out->patch = (int)version_info->GetPatch();
 
     // copy pre_release, needs local variable because out->pre_release is const
-    char *pre_release = (char *)malloc(sizeof(char) * (version_info->GetPreRelease().length() + 1));
+    auto *pre_release = (char *)malloc(sizeof(char) * (version_info->GetPreRelease().length() + 1));
     strcpy(pre_release, version_info->GetPreRelease().c_str());
     out->pre_release = pre_release;
 
     // copy build, needs local variable because out->build is const
-    char *build = (char *)malloc(sizeof(char) * (version_info->GetBuild().length() + 1));
+    auto *build = (char *)malloc(sizeof(char) * (version_info->GetBuild().length() + 1));
     strcpy(build, version_info->GetBuild().c_str());
     out->build = build;
 
@@ -413,6 +413,16 @@ ERROR_RETURN_CODE(GENERIC_ERROR,
                     return wrapped_transaction->RetrieveById(std::string(id));
                   })
 
+ERROR_RETURN_CODE(GENERIC_ERROR,
+                  int caosdb_transaction_transaction_retrieve_and_download_file_by_id(
+                    caosdb_transaction_transaction *transaction, const char *id, const char *path),
+                  {
+                    auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>(
+                      transaction->wrapped_transaction);
+                    return wrapped_transaction->RetrieveAndDownloadFileById(std::string(id),
+                                                                            std::string(path));
+                  })
+
 ERROR_RETURN_CODE(GENERIC_ERROR,
                   int caosdb_transaction_transaction_retrieve_by_ids(
                     caosdb_transaction_transaction *transaction, const char *ids[], int length),
@@ -431,6 +441,40 @@ ERROR_RETURN_CODE(GENERIC_ERROR,
                     return wrapped_transaction->Query(std::string(query));
                   })
 
+ERROR_RETURN_CODE(
+  GENERIC_ERROR,
+  int caosdb_transaction_transaction_insert_entity(caosdb_transaction_transaction *transaction,
+                                                   caosdb_entity_entity *entity),
+  {
+    auto *wrapped_transaction =
+      static_cast<caosdb::transaction::Transaction *>(transaction->wrapped_transaction);
+    auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
+
+    return wrapped_transaction->InsertEntity(wrapped_entity);
+  })
+
+ERROR_RETURN_CODE(
+  GENERIC_ERROR,
+  int caosdb_transaction_transaction_update_entity(caosdb_transaction_transaction *transaction,
+                                                   caosdb_entity_entity *entity),
+  {
+    auto *wrapped_transaction =
+      static_cast<caosdb::transaction::Transaction *>(transaction->wrapped_transaction);
+    auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
+
+    return wrapped_transaction->UpdateEntity(wrapped_entity);
+  })
+
+ERROR_RETURN_CODE(GENERIC_ERROR,
+                  int caosdb_transaction_transaction_delete_by_id(
+                    caosdb_transaction_transaction *transaction, const char *id),
+                  {
+                    auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>(
+                      transaction->wrapped_transaction);
+
+                    return wrapped_transaction->DeleteById(std::string(id));
+                  })
+
 ERROR_RETURN_CODE(
   GENERIC_ERROR,
   int caosdb_transaction_transaction_execute(caosdb_transaction_transaction *transaction), {
@@ -544,13 +588,25 @@ ERROR_RETURN_CODE(GENERIC_ERROR,
                   int caosdb_entity_entity_get_role(caosdb_entity_entity *entity, char **out), {
                     auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
                     std::string role_str = ENUM_NAME_FROM_VALUE(wrapped_entity->GetRole(), Role);
-                    char *tmp = (char *)malloc(sizeof(char) * role_str.length() + 1);
+                    auto *tmp = (char *)malloc(sizeof(char) * role_str.length() + 1);
                     strcpy(tmp, role_str.c_str());
                     delete[] * out;
                     *out = tmp;
                     return 0;
                   })
 CAOSDB_ENTITY_GET(name, GetName())
+ERROR_RETURN_CODE(GENERIC_ERROR,
+                  int caosdb_entity_entity_get_local_path(caosdb_entity_entity *entity, char **out),
+                  {
+                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
+                    auto path = wrapped_entity->GetLocalPath().string();
+                    auto *tmp = (char *)(malloc(sizeof(char) * path.length() + 1));
+                    strcpy(tmp, path.c_str());
+                    delete[] * out;
+                    *out = tmp;
+                    return 0;
+                  })
+// CAOSDB_ENTITY_GET(file_path, GetFilePath()) TODO(henrik)
 CAOSDB_ENTITY_GET(description, GetDescription())
 ERROR_RETURN_CODE(GENERIC_ERROR,
                   int caosdb_entity_entity_get_datatype(caosdb_entity_entity *entity, char **name,
@@ -895,7 +951,7 @@ ERROR_RETURN_CODE(GENERIC_ERROR,
                   {
                     auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
                     auto value_list = wrapped_property->GetValue().AsList();
-                    char *tmp =
+                    auto *tmp =
                       (char *)malloc(sizeof(char) * value_list[index].AsString().length() + 1);
                     strcpy(tmp, value_list[index].AsString().c_str());
                     delete[] * out;
@@ -928,7 +984,7 @@ ERROR_RETURN_CODE(
   GENERIC_ERROR,
   int caosdb_entity_message_get_description(caosdb_entity_message *message, char **out), {
     auto *wrapped_message = static_cast<caosdb::entity::Message *>(message->wrapped_message);
-    char *tmp = (char *)malloc(sizeof(char) * wrapped_message->GetDescription().length() + 1);
+    auto *tmp = (char *)malloc(sizeof(char) * wrapped_message->GetDescription().length() + 1);
     strcpy(tmp, wrapped_message->GetDescription().c_str());
     delete[] * out;
     *out = tmp;
@@ -949,6 +1005,9 @@ ERROR_RETURN_CODE(GENERIC_ERROR,
                     }
                   })
 CAOSDB_ENTITY_SET(name, name, wrapped_entity->SetName(std::string(name));)
+CAOSDB_ENTITY_SET(local_path, local_path,
+                  return wrapped_entity->SetLocalPath(boost::filesystem::path(local_path));)
+CAOSDB_ENTITY_SET(file_path, file_path, wrapped_entity->SetFilePath(std::string(file_path));)
 CAOSDB_ENTITY_SET(description, description,
                   wrapped_entity->SetDescription(std::string(description));)
 ERROR_RETURN_CODE(GENERIC_ERROR,
diff --git a/test/test_ccaosdb.cpp b/test/test_ccaosdb.cpp
index c68d4ef14df142fcb6e8d75df51c89cf59cb0101..fe9142862b1b4da10f23db06a2a20abe529ae35a 100644
--- a/test/test_ccaosdb.cpp
+++ b/test/test_ccaosdb.cpp
@@ -152,6 +152,16 @@ TEST_F(test_ccaosdb, test_entity) {
   EXPECT_EQ(return_code, 0);
   EXPECT_EQ(strcmp(out, "length"), 0);
 
+  // test call without validation of result
+  return_code = caosdb_entity_entity_set_role(&entity, "FILE");
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_entity_set_local_path(
+    &entity, (TEST_DATA_DIR + "/test_caosdb_client.json").c_str());
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_entity_get_local_path(&entity, &out);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_EQ(strcmp(out, (TEST_DATA_DIR + "/test_caosdb_client.json").c_str()), 0);
+
   // invalid role
   return_code = caosdb_entity_entity_set_role(&entity, "Role does not exist");
   EXPECT_EQ(return_code, caosdb::StatusCode::ENUM_MAPPING_ERROR);
@@ -453,3 +463,42 @@ TEST_F(test_ccaosdb, test_remove_property) {
   return_code = caosdb_entity_delete_entity(&entity);
   EXPECT_EQ(return_code, 0);
 }
+
+TEST_F(test_ccaosdb, test_insert_update_delete) {
+  // Only test adding to a transaction.  Excution and results are
+  // tested in integration tests.
+  caosdb_connection_connection connection;
+  caosdb_connection_connection_manager_get_default_connection(&connection);
+
+  caosdb_transaction_transaction insert_transaction;
+  caosdb_connection_connection_create_transaction(&connection, &insert_transaction);
+
+  caosdb_entity_entity entity;
+  caosdb_entity_create_entity(&entity);
+  caosdb_entity_entity_set_name(&entity, "some_name");
+  caosdb_entity_entity_set_local_path(&entity, "some_name");
+  caosdb_entity_entity_set_file_path(&entity, "some_name");
+
+  auto return_code = caosdb_transaction_transaction_insert_entity(&insert_transaction, &entity);
+  // For now, nothing further can be done here, so it should be READY
+  EXPECT_EQ(return_code, caosdb::StatusCode::READY);
+
+  caosdb_transaction_transaction update_transaction;
+  caosdb_connection_connection_create_transaction(&connection, &update_transaction);
+
+  return_code = caosdb_transaction_transaction_update_entity(&update_transaction, &entity);
+  // No ID, so this should be an error
+  EXPECT_EQ(return_code, caosdb::StatusCode::ORIGINAL_ENTITY_MISSING_ID);
+
+  caosdb_transaction_transaction delete_transaction;
+  caosdb_connection_connection_create_transaction(&connection, &delete_transaction);
+
+  return_code = caosdb_transaction_transaction_delete_by_id(&delete_transaction, "some_id");
+  // Could add further deletions
+  EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON);
+
+  caosdb_entity_delete_entity(&entity);
+  caosdb_transaction_delete_transaction(&insert_transaction);
+  caosdb_transaction_delete_transaction(&update_transaction);
+  caosdb_transaction_delete_transaction(&delete_transaction);
+}
diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp
index 21c00f86b20758e03dc6f1d78e4aad11b469479e..db2d76a845f5548eb68570d183e1a7867a91fe15 100644
--- a/test/test_transaction.cpp
+++ b/test/test_transaction.cpp
@@ -199,7 +199,7 @@ TEST(test_transaction, test_retrieve_and_download) {
   auto transaction = connection.CreateTransaction();
 
   EXPECT_EQ(transaction->GetStatus().GetCode(), StatusCode::INITIAL);
-  transaction->RetrieveAndDownloadFilesById("asdf", "local_path");
+  transaction->RetrieveAndDownloadFileById("asdf", "local_path");
 
   EXPECT_EQ(transaction->GetStatus().GetCode(), StatusCode::GO_ON);