diff --git a/lib/types/crypto-types.js b/lib/types/crypto-types.js
--- a/lib/types/crypto-types.js
+++ b/lib/types/crypto-types.js
@@ -45,6 +45,11 @@
   +notificationsOneTimeKeys: OLMOneTimeKeys,
 };
 
+export type OneTimeKeysResultValues = {
+  +contentOneTimeKeys: $ReadOnlyArray<string>,
+  +notificationsOneTimeKeys: $ReadOnlyArray<string>,
+};
+
 export type PickledOLMAccount = {
   +picklingKey: string,
   +pickledAccount: string,
diff --git a/lib/types/identity-service-types.js b/lib/types/identity-service-types.js
--- a/lib/types/identity-service-types.js
+++ b/lib/types/identity-service-types.js
@@ -7,6 +7,7 @@
   type IdentityKeysBlob,
   signedPrekeysValidator,
   type SignedPrekeys,
+  type OneTimeKeysResultValues,
 } from './crypto-types.js';
 import {
   type OlmSessionInitializationInfo,
@@ -112,6 +113,7 @@
   +getInboundKeysForUser: (
     userID: string,
   ) => Promise<UserDevicesOlmInboundKeys>;
+  +uploadOneTimeKeys: (oneTimeKeys: OneTimeKeysResultValues) => Promise<void>;
   +generateNonce: () => Promise<string>;
   +registerWalletUser?: (
     walletAddress: string,
diff --git a/native/identity-service/identity-service-context-provider.react.js b/native/identity-service/identity-service-context-provider.react.js
--- a/native/identity-service/identity-service-context-provider.react.js
+++ b/native/identity-service/identity-service-context-provider.react.js
@@ -7,6 +7,7 @@
 import {
   type IdentityKeysBlob,
   identityKeysBlobValidator,
+  type OneTimeKeysResultValues,
 } from 'lib/types/crypto-types.js';
 import {
   type DeviceOlmOutboundKeys,
@@ -268,6 +269,21 @@
           userDeviceOlmInboundKeysValidator,
         );
       },
+      uploadOneTimeKeys: async (oneTimeKeys: OneTimeKeysResultValues) => {
+        const {
+          deviceID: authDeviceID,
+          userID,
+          accessToken: token,
+        } = await getAuthMetadata();
+
+        await commRustModule.uploadOneTimeKeys(
+          userID,
+          authDeviceID,
+          token,
+          oneTimeKeys.contentOneTimeKeys,
+          oneTimeKeys.notificationsOneTimeKeys,
+        );
+      },
       registerPasswordUser: async (username: string, password: string) => {
         await commCoreModule.initializeCryptoAccount();
         const [
diff --git a/web/grpc/identity-service-client-wrapper.js b/web/grpc/identity-service-client-wrapper.js
--- a/web/grpc/identity-service-client-wrapper.js
+++ b/web/grpc/identity-service-client-wrapper.js
@@ -3,6 +3,7 @@
 import { Login } from '@commapp/opaque-ke-wasm';
 
 import identityServiceConfig from 'lib/facts/identity-service.js';
+import type { OneTimeKeysResultValues } from 'lib/types/crypto-types.js';
 import {
   type IdentityServiceAuthLayer,
   type IdentityServiceClient,
@@ -295,6 +296,22 @@
     );
   };
 
+  uploadOneTimeKeys: (oneTimeKeys: OneTimeKeysResultValues) => Promise<void> =
+    async (oneTimeKeys: OneTimeKeysResultValues) => {
+      const client = this.authClient;
+      if (!client) {
+        throw new Error('Identity service client is not initialized');
+      }
+
+      const contentOneTimeKeysArray = [...oneTimeKeys.contentOneTimeKeys];
+      const notifOneTimeKeysArray = [...oneTimeKeys.notificationsOneTimeKeys];
+
+      const request = new IdentityAuthStructs.UploadOneTimeKeysRequest();
+      request.setContentOneTimePrekeysList(contentOneTimeKeysArray);
+      request.setNotifOneTimePrekeysList(notifOneTimeKeysArray);
+      await client.uploadOneTimeKeys(request);
+    };
+
   logInPasswordUser: (
     username: string,
     password: string,