diff --git a/packages/collaborator-client/src/client.ts b/packages/collaborator-client/src/client.ts
index 4d2f7b2391..1448bc11ee 100644
--- a/packages/collaborator-client/src/client.ts
+++ b/packages/collaborator-client/src/client.ts
@@ -13,7 +13,8 @@
 // limitations under the License.
 //
 
-import { Class, Doc, Markup, Ref, concatLink } from '@hcengineering/core'
+import { Class, Doc, Hierarchy, Markup, Ref, concatLink } from '@hcengineering/core'
+import { minioDocumentId, mongodbDocumentId } from './utils'
 
 /**
  * @public
@@ -26,18 +27,32 @@ export interface CollaboratorClient {
 /**
  * @public
  */
-export function getClient (token: string, collaboratorUrl: string): CollaboratorClient {
-  return new CollaboratorClientImpl(token, collaboratorUrl)
+export function getClient (hierarchy: Hierarchy, token: string, collaboratorUrl: string): CollaboratorClient {
+  return new CollaboratorClientImpl(hierarchy, token, collaboratorUrl)
 }
 
 class CollaboratorClientImpl implements CollaboratorClient {
   constructor (
+    private readonly hierarchy: Hierarchy,
     private readonly token: string,
     private readonly collaboratorUrl: string
   ) {}
 
+  initialContentId (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): string {
+    const domain = this.hierarchy.getDomain(classId)
+    return mongodbDocumentId(domain, docId, attribute)
+  }
+
   async get (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): Promise<Markup> {
-    const url = concatLink(this.collaboratorUrl, `/api/content/${classId}/${docId}/${attribute}`)
+    const documentId = encodeURIComponent(minioDocumentId(docId, attribute))
+    const initialContentId = encodeURIComponent(this.initialContentId(classId, docId, attribute))
+    attribute = encodeURIComponent(attribute)
+
+    const url = concatLink(
+      this.collaboratorUrl,
+      `/api/content/${documentId}/${attribute}?initialContentId=${initialContentId}`
+    )
+
     const res = await fetch(url, {
       method: 'GET',
       headers: {
@@ -50,7 +65,15 @@ class CollaboratorClientImpl implements CollaboratorClient {
   }
 
   async update (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string, value: Markup): Promise<void> {
-    const url = concatLink(this.collaboratorUrl, `/api/content/${classId}/${docId}/${attribute}`)
+    const documentId = encodeURIComponent(minioDocumentId(docId, attribute))
+    const initialContentId = encodeURIComponent(this.initialContentId(classId, docId, attribute))
+    attribute = encodeURIComponent(attribute)
+
+    const url = concatLink(
+      this.collaboratorUrl,
+      `/api/content/${documentId}/${attribute}?initialContentId=${initialContentId}`
+    )
+
     await fetch(url, {
       method: 'PUT',
       headers: {
diff --git a/packages/collaborator-client/src/index.ts b/packages/collaborator-client/src/index.ts
index 14e78297e9..2ac44b392f 100644
--- a/packages/collaborator-client/src/index.ts
+++ b/packages/collaborator-client/src/index.ts
@@ -14,3 +14,4 @@
 //
 
 export { type CollaboratorClient, getClient } from './client'
+export * from './utils'
diff --git a/packages/collaborator-client/src/utils.ts b/packages/collaborator-client/src/utils.ts
new file mode 100644
index 0000000000..9ce34ca636
--- /dev/null
+++ b/packages/collaborator-client/src/utils.ts
@@ -0,0 +1,24 @@
+//
+// Copyright © 2024 Hardcore Engineering Inc.
+//
+// Licensed under the Eclipse Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License. You may
+// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+import { Doc, Domain, Ref } from '@hcengineering/core'
+
+export function minioDocumentId (docId: Ref<Doc>, attribute?: string): string {
+  return attribute !== undefined ? `minio://${docId}%${attribute}` : `minio://${docId}`
+}
+
+export function mongodbDocumentId (domain: Domain, docId: Ref<Doc>, attribute: string): string {
+  return `mongodb://${domain}/${docId}/${attribute}`
+}
diff --git a/packages/presentation/src/collaborator.ts b/packages/presentation/src/collaborator.ts
index 9211689f31..600f0c95ae 100644
--- a/packages/presentation/src/collaborator.ts
+++ b/packages/presentation/src/collaborator.ts
@@ -13,20 +13,22 @@
 // limitations under the License.
 //
 
-import { type CollaboratorClient, getClient } from '@hcengineering/collaborator-client'
+import { type CollaboratorClient, getClient as getCollaborator } from '@hcengineering/collaborator-client'
 import type { Class, Doc, Markup, Ref } from '@hcengineering/core'
 import { getMetadata } from '@hcengineering/platform'
 
+import { getClient } from '.'
 import presentation from './plugin'
 
 /**
  * @public
  */
 export function getCollaboratorClient (): CollaboratorClient {
+  const hierarchy = getClient().getHierarchy()
   const token = getMetadata(presentation.metadata.Token) ?? ''
   const collaboratorURL = getMetadata(presentation.metadata.CollaboratorUrl) ?? ''
 
-  return getClient(token, collaboratorURL)
+  return getCollaborator(hierarchy, token, collaboratorURL)
 }
 
 /**
diff --git a/server/collaborator/src/server.ts b/server/collaborator/src/server.ts
index f809881935..6a50d37424 100644
--- a/server/collaborator/src/server.ts
+++ b/server/collaborator/src/server.ts
@@ -153,18 +153,18 @@ export async function start (
 
   const restCtx = ctx.newChild('REST', {})
 
-  const getContext = (token: Token, documentId: string): Context => {
+  const getContext = (token: Token, initialContentId?: string): Context => {
     return {
       connectionId: generateId(),
       workspaceId: token.workspace,
       clientFactory: getClientFactory(token, controller),
-      initialContentId: documentId,
+      initialContentId: initialContentId ?? '',
       targetContentId: ''
     }
   }
 
   // eslint-disable-next-line @typescript-eslint/no-misused-promises
-  app.get('/api/content/:classId/:docId/:attribute', async (req, res) => {
+  app.get('/api/content/:documentId/:field', async (req, res) => {
     console.log('handle request', req.method, req.url)
 
     const authHeader = req.headers.authorization
@@ -176,22 +176,21 @@ export async function start (
     const token = authHeader.split(' ')[1]
     const decodedToken = decodeToken(token)
 
-    const docId = req.params.docId
-    const attribute = req.params.attribute
+    const documentId = req.params.documentId
+    const field = req.params.field
+    const initialContentId = req.query.initialContentId as string
 
-    if (docId === undefined || docId === '') {
-      res.status(400).send({ err: "'docId' is missing" })
+    if (documentId === undefined || documentId === '') {
+      res.status(400).send({ err: "'documentId' is missing" })
       return
     }
 
-    if (attribute === undefined || attribute === '') {
-      res.status(400).send({ err: "'attribute' is missing" })
+    if (field === undefined || field === '') {
+      res.status(400).send({ err: "'field' is missing" })
       return
     }
 
-    const documentId = `minio://${docId}%${attribute}`
-
-    const context = getContext(decodedToken, documentId)
+    const context = getContext(decodedToken, initialContentId)
 
     await restCtx.with(`${req.method} /content`, {}, async (ctx) => {
       const connection = await ctx.with('connect', {}, async () => {
@@ -202,7 +201,7 @@ export async function start (
         const html = await ctx.with('transform', {}, async () => {
           let content = ''
           await connection.transact((document) => {
-            content = transformer.fromYdoc(document, attribute)
+            content = transformer.fromYdoc(document, field)
           })
           return content
         })
@@ -221,7 +220,7 @@ export async function start (
   })
 
   // eslint-disable-next-line @typescript-eslint/no-misused-promises
-  app.put('/api/content/:classId/:docId/:attribute', async (req, res) => {
+  app.put('/api/content/:documentId/:field', async (req, res) => {
     console.log('handle request', req.method, req.url)
 
     const authHeader = req.headers.authorization
@@ -233,27 +232,26 @@ export async function start (
     const token = authHeader.split(' ')[1]
     const decodedToken = decodeToken(token)
 
-    const docId = req.params.docId
-    const attribute = req.params.attribute
-
-    if (docId === undefined || docId === '') {
-      res.status(400).send({ err: "'docId' is missing" })
-      return
-    }
-
-    if (attribute === undefined || attribute === '') {
-      res.status(400).send({ err: "'attribute' is missing" })
-      return
-    }
-
-    const documentId = `minio://${docId}%${attribute}`
+    const documentId = req.params.documentId
+    const field = req.params.field
+    const initialContentId = req.query.initialContentId as string
     const data = req.body.html ?? '<p></p>'
 
-    const context = getContext(decodedToken, documentId)
+    if (documentId === undefined || documentId === '') {
+      res.status(400).send({ err: "'documentId' is missing" })
+      return
+    }
+
+    if (field === undefined || field === '') {
+      res.status(400).send({ err: "'field' is missing" })
+      return
+    }
+
+    const context = getContext(decodedToken, initialContentId)
 
     await restCtx.with(`${req.method} /content`, {}, async (ctx) => {
       const update = await ctx.with('transform', {}, () => {
-        const ydoc = transformer.toYdoc(data, attribute)
+        const ydoc = transformer.toYdoc(data, field)
         return encodeStateAsUpdate(ydoc)
       })
 
@@ -264,7 +262,7 @@ export async function start (
       try {
         await ctx.with('update', {}, async () => {
           await connection.transact((document) => {
-            const fragment = document.getXmlFragment(attribute)
+            const fragment = document.getXmlFragment(field)
             document.transact((tr) => {
               fragment.delete(0, fragment.length)
               applyUpdate(document, update)