diff --git a/Sources/XXMessengerClient/Messenger/Functions/MessengerRegisterForNotifications.swift b/Sources/XXMessengerClient/Messenger/Functions/MessengerRegisterForNotifications.swift
new file mode 100644
index 0000000000000000000000000000000000000000..b39b933e2abb297bb49b86b0f9348602949c5426
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functions/MessengerRegisterForNotifications.swift
@@ -0,0 +1,35 @@
+import Foundation
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerRegisterForNotifications {
+  public enum Error: Swift.Error, Equatable {
+    case notConnected
+  }
+
+  public var run: (Data) throws -> Void
+
+  public func callAsFunction(token: Data) throws -> Void {
+    try run(token)
+  }
+}
+
+extension MessengerRegisterForNotifications {
+  public static func live(_ env: MessengerEnvironment) -> MessengerRegisterForNotifications {
+    MessengerRegisterForNotifications { token in
+      guard let e2e = env.e2e() else {
+        throw Error.notConnected
+      }
+      try env.registerForNotifications(
+        e2eId: e2e.getId(),
+        token: token.map { String(format: "%02hhx", $0) }.joined()
+      )
+    }
+  }
+}
+
+extension MessengerRegisterForNotifications {
+  public static let unimplemented = MessengerRegisterForNotifications(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 3fd872c6b3b4bf6ce546081dbbec93c86bd8695a..cc48651c730cd7cce79aa7fda28265d4fa6ea5a1 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -20,6 +20,7 @@ public struct Messenger {
   public var waitForNodes: MessengerWaitForNodes
   public var destroy: MessengerDestroy
   public var searchUsers: MessengerSearchUsers
+  public var registerForNotifications: MessengerRegisterForNotifications
 }
 
 extension Messenger {
@@ -43,7 +44,8 @@ extension Messenger {
       waitForNetwork: .live(env),
       waitForNodes: .live(env),
       destroy: .live(env),
-      searchUsers: .live(env)
+      searchUsers: .live(env),
+      registerForNotifications: .live(env)
     )
   }
 }
@@ -68,6 +70,7 @@ extension Messenger {
     waitForNetwork: .unimplemented,
     waitForNodes: .unimplemented,
     destroy: .unimplemented,
-    searchUsers: .unimplemented
+    searchUsers: .unimplemented,
+    registerForNotifications: .unimplemented
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index f846117fc0b178e0f8161f50678b7967f6a1dc2c..85e53d0b99599b70136dfb1a5c30144e4564613c 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -19,6 +19,7 @@ public struct MessengerEnvironment {
   public var newCMix: NewCMix
   public var newOrLoadUd: NewOrLoadUd
   public var passwordStorage: PasswordStorage
+  public var registerForNotifications: RegisterForNotifications
   public var searchUD: SearchUD
   public var sleep: (TimeInterval) -> Void
   public var storageDir: String
@@ -53,6 +54,7 @@ extension MessengerEnvironment {
       newCMix: .live,
       newOrLoadUd: .live,
       passwordStorage: .keychain,
+      registerForNotifications: .live,
       searchUD: .live,
       sleep: { Thread.sleep(forTimeInterval: $0) },
       storageDir: MessengerEnvironment.defaultStorageDir,
@@ -82,6 +84,7 @@ extension MessengerEnvironment {
     newCMix: .unimplemented,
     newOrLoadUd: .unimplemented,
     passwordStorage: .unimplemented,
+    registerForNotifications: .unimplemented,
     searchUD: .unimplemented,
     sleep: XCTUnimplemented("\(Self.self).sleep"),
     storageDir: "unimplemented",
diff --git a/Tests/XXMessengerClientTests/Messenger/Functions/MessengerRegisterForNotificationsTests.swift b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerRegisterForNotificationsTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..de4f691910263e1ef7e8402977edf662efa45d47
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerRegisterForNotificationsTests.swift
@@ -0,0 +1,61 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerRegisterForNotificationsTest: XCTestCase {
+  func testRegister() throws {
+    struct DidRegister: Equatable {
+      var e2eId: Int
+      var token: String
+    }
+    var didRegister: [DidRegister] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      return e2e
+    }
+    env.registerForNotifications.run = { e2eId, token in
+      didRegister.append(.init(e2eId: e2eId, token: token))
+    }
+
+    let register: MessengerRegisterForNotifications = .live(env)
+    let token = "test-token".data(using: .utf8)!
+
+    try register(token: token)
+
+    XCTAssertNoDifference(didRegister, [.init(e2eId: 1234, token: "746573742d746f6b656e")])
+  }
+
+  func testRegisterWhenNotConnected() {
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = { nil }
+    let register: MessengerRegisterForNotifications = .live(env)
+    let token = "test-token".data(using: .utf8)!
+
+    XCTAssertThrowsError(try register(token: token)) { error in
+      XCTAssertEqual(error as? MessengerRegisterForNotifications.Error, .notConnected)
+    }
+  }
+
+  func testRegisterFailure() {
+    struct Failure: Error, Equatable {}
+    let failure = Failure()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      return e2e
+    }
+    env.registerForNotifications.run = { _, _ in throw failure }
+    let register: MessengerRegisterForNotifications = .live(env)
+    let token = "test-token".data(using: .utf8)!
+
+    XCTAssertThrowsError(try register(token: token)) { error in
+      XCTAssertEqual(error as? Failure, failure)
+    }
+  }
+}