diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.h b/native/cpp/CommonCpp/NativeModules/CommRustModule.h
--- a/native/cpp/CommonCpp/NativeModules/CommRustModule.h
+++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.h
@@ -73,6 +73,13 @@
       jsi::String authAccessToken,
       jsi::String userID) override;
   virtual jsi::Value versionSupported(jsi::Runtime &rt) override;
+  virtual jsi::Value uploadOneTimeKeys(
+      jsi::Runtime &rt,
+      jsi::String authUserID,
+      jsi::String authDeviceID,
+      jsi::String authAccessToken,
+      jsi::Array contentOneTimePreKeys,
+      jsi::Array notifOneTimePreKeys) override;
 
 public:
   CommRustModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker);
diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp
--- a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp
+++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp
@@ -285,4 +285,37 @@
       });
 }
 
+jsi::Value CommRustModule::uploadOneTimeKeys(
+    jsi::Runtime &rt,
+    jsi::String authUserID,
+    jsi::String authDeviceID,
+    jsi::String authAccessToken,
+    jsi::Array contentOneTimePreKeys,
+    jsi::Array notifOneTimePreKeys) {
+  return createPromiseAsJSIValue(
+      rt,
+      [this,
+       &authUserID,
+       &authDeviceID,
+       &authAccessToken,
+       &contentOneTimePreKeys,
+       &notifOneTimePreKeys](
+          jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
+        std::string error;
+        try {
+          auto currentID = RustPromiseManager::instance.addPromise(
+              promise, this->jsInvoker_, innerRt);
+          identityUploadOneTimeKeys(
+              jsiStringToRustString(authUserID, innerRt),
+              jsiStringToRustString(authDeviceID, innerRt),
+              jsiStringToRustString(authAccessToken, innerRt),
+              jsiStringArrayToRustVec(contentOneTimePreKeys, innerRt),
+              jsiStringArrayToRustVec(notifOneTimePreKeys, innerRt),
+              currentID);
+        } catch (const std::exception &e) {
+          error = e.what();
+        };
+      });
+}
+
 } // namespace comm
diff --git a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp
--- a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp
+++ b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp
@@ -39,6 +39,9 @@
 static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_versionSupported(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
   return static_cast<CommRustModuleSchemaCxxSpecJSI *>(&turboModule)->versionSupported(rt);
 }
+static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_uploadOneTimeKeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
+  return static_cast<CommRustModuleSchemaCxxSpecJSI *>(&turboModule)->uploadOneTimeKeys(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asObject(rt).asArray(rt), args[4].asObject(rt).asArray(rt));
+}
 
 CommRustModuleSchemaCxxSpecJSI::CommRustModuleSchemaCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
   : TurboModule("CommRustTurboModule", jsInvoker) {
@@ -51,6 +54,7 @@
   methodMap_["getOutboundKeysForUser"] = MethodMetadata {4, __hostFunction_CommRustModuleSchemaCxxSpecJSI_getOutboundKeysForUser};
   methodMap_["getInboundKeysForUser"] = MethodMetadata {4, __hostFunction_CommRustModuleSchemaCxxSpecJSI_getInboundKeysForUser};
   methodMap_["versionSupported"] = MethodMetadata {0, __hostFunction_CommRustModuleSchemaCxxSpecJSI_versionSupported};
+  methodMap_["uploadOneTimeKeys"] = MethodMetadata {5, __hostFunction_CommRustModuleSchemaCxxSpecJSI_uploadOneTimeKeys};
 }
 
 
diff --git a/native/cpp/CommonCpp/_generated/rustJSI.h b/native/cpp/CommonCpp/_generated/rustJSI.h
--- a/native/cpp/CommonCpp/_generated/rustJSI.h
+++ b/native/cpp/CommonCpp/_generated/rustJSI.h
@@ -29,6 +29,7 @@
   virtual jsi::Value getOutboundKeysForUser(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::String userID) = 0;
   virtual jsi::Value getInboundKeysForUser(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::String userID) = 0;
   virtual jsi::Value versionSupported(jsi::Runtime &rt) = 0;
+  virtual jsi::Value uploadOneTimeKeys(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::Array contentOneTimePreKeys, jsi::Array notifOneTimePreKeys) = 0;
 
 };
 
@@ -122,6 +123,14 @@
       return bridging::callFromJs<jsi::Value>(
           rt, &T::versionSupported, jsInvoker_, instance_);
     }
+    jsi::Value uploadOneTimeKeys(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::Array contentOneTimePreKeys, jsi::Array notifOneTimePreKeys) override {
+      static_assert(
+          bridging::getParameterCount(&T::uploadOneTimeKeys) == 6,
+          "Expected uploadOneTimeKeys(...) to have 6 parameters");
+
+      return bridging::callFromJs<jsi::Value>(
+          rt, &T::uploadOneTimeKeys, jsInvoker_, instance_, std::move(authUserID), std::move(authDeviceID), std::move(authAccessToken), std::move(contentOneTimePreKeys), std::move(notifOneTimePreKeys));
+    }
 
   private:
     T *instance_;
diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs
--- a/native/native_rust_library/src/lib.rs
+++ b/native/native_rust_library/src/lib.rs
@@ -5,7 +5,7 @@
 use grpc_clients::identity::protos::authenticated::{
   InboundKeyInfo, InboundKeysForUserRequest, OutboundKeyInfo,
   OutboundKeysForUserRequest, UpdateUserPasswordFinishRequest,
-  UpdateUserPasswordStartRequest,
+  UpdateUserPasswordStartRequest, UploadOneTimeKeysRequest,
 };
 use grpc_clients::identity::protos::client::{
   DeviceKeyUpload, DeviceType, Empty, IdentityKeyInfo,
@@ -140,6 +140,16 @@
     #[cxx_name = "identityVersionSupported"]
     fn version_supported(promise_id: u32);
 
+    #[cxx_name = "identityUploadOneTimeKeys"]
+    fn upload_one_time_keys(
+      auth_user_id: String,
+      auth_device_id: String,
+      auth_access_token: String,
+      content_one_time_keys: Vec<String>,
+      notif_one_time_keys: Vec<String>,
+      promise_id: u32,
+    );
+
     // Argon2
     #[cxx_name = "compute_backup_key"]
     fn compute_backup_key_str(
@@ -1012,6 +1022,49 @@
   Ok(serde_json::to_string(&inbound_key_info)?)
 }
 
+#[instrument]
+fn upload_one_time_keys(
+  auth_user_id: String,
+  auth_device_id: String,
+  auth_access_token: String,
+  content_one_time_keys: Vec<String>,
+  notif_one_time_keys: Vec<String>,
+  promise_id: u32,
+) {
+  RUNTIME.spawn(async move {
+    let upload_request = UploadOneTimeKeysRequest {
+      content_one_time_pre_keys: content_one_time_keys,
+      notif_one_time_pre_keys: notif_one_time_keys,
+    };
+    let auth_info = AuthInfo {
+      access_token: auth_access_token,
+      user_id: auth_user_id,
+      device_id: auth_device_id,
+    };
+    let result = upload_one_time_keys_helper(auth_info, upload_request).await;
+    handle_void_result_as_callback(result, promise_id);
+  });
+}
+
+async fn upload_one_time_keys_helper(
+  auth_info: AuthInfo,
+  upload_request: UploadOneTimeKeysRequest,
+) -> Result<(), Error> {
+  let mut identity_client = get_auth_client(
+    IDENTITY_SOCKET_ADDR,
+    auth_info.user_id,
+    auth_info.device_id,
+    auth_info.access_token,
+    CODE_VERSION,
+    DEVICE_TYPE.as_str_name().to_lowercase(),
+  )
+  .await?;
+
+  identity_client.upload_one_time_keys(upload_request).await?;
+
+  Ok(())
+}
+
 #[derive(
   Debug, derive_more::Display, derive_more::From, derive_more::Error,
 )]
diff --git a/native/schema/CommRustModuleSchema.js b/native/schema/CommRustModuleSchema.js
--- a/native/schema/CommRustModuleSchema.js
+++ b/native/schema/CommRustModuleSchema.js
@@ -68,6 +68,13 @@
     userID: string,
   ) => Promise<string>;
   +versionSupported: () => Promise<boolean>;
+  +uploadOneTimeKeys: (
+    authUserID: string,
+    authDeviceID: string,
+    authAccessToken: string,
+    contentOneTimePreKeys: $ReadOnlyArray<string>,
+    notifOneTimePreKeys: $ReadOnlyArray<string>,
+  ) => Promise<void>;
 }
 
 export default (TurboModuleRegistry.getEnforcing<Spec>(