Inject content REST API

Available in Team plan

To inject content into documents server-side, use the PATCH endpoint described in this document. This feature supports version history, tracking changes as well as content added through this endpoint.

The update document endpoint also allows JSON updates to modify documents on your Collaboration server, both On-Premises and Cloud:

  • Add json, binary, or base64 content to any document server-side.
  • Inject content into specific nodes using the UniqueID extension.
  • Users can still collaborate in real-time as content is injected.
  • Track user and injected content changes, fully compatible with Snapshots.

Use cases

The content injection REST API enables a couple of handy but sophisticated use cases:

  • Live translation of document content.
  • Programmatically tagging or manipulating document content server-side.
  • Integrating server-side components, like executing SQL queries and displaying results.
  • Version history integration and conflict-free merging of concurrent edits.

Create a document

To seed a new document on the Tiptap Collab server, use the POST method with the following endpoint:

POST /api/documents/:identifier?format=:format

The server will return HTTP status 204 for successful creation, 409 if the document already exists (you must delete it first to overwrite), and 422 if the action failed.

The format parameter accepts the same values as the update endpoint (binary, base64, or json).

Update a document

To update an existing document on the Collaboration server, you can use the PATCH method with the following API endpoint:

PATCH /api/documents/:identifier?format=:format

This endpoint accepts a Yjs update message and applies it to the specified document.

Query parameters

ParameterTypeDefaultDescription
formatstringThe format of the update: json, binary (Yjs's Y.encodeStateAsUpdate), or base64 (binary state encoded as Base64).
modestringdefaultThe update strategy: default merges nodes, append appends only, node replaces matched nodes with the payload, attrs replaces attributes of matched nodes, delete deletes matched nodes (no payload needed). See modes.
nodeAttributeNamestringLimit the update to nodes with an attribute of this name. Used together with nodeAttributeValue.
nodeAttributeValuestringLimit the update to nodes with an attribute of this value. Used together with nodeAttributeName. You can pass multiple values: ?nodeAttributeValue=a&nodeAttributeValue=b.
checksumstringOnly apply the update if the document's current state matches this checksum (returned as x-FRAGMENTNAME-checksum in the get document response). Returns 409 Checksum mismatch otherwise.
userstringUser ID to associate with the change.
skipVersioning1If passed, auto versioning won't be triggered by this change.
fragmentstringdefaultYjs fragment to update. You can update multiple fragments with the same content (when format=json) by passing multiple values: ?fragment=a&fragment=b.
mergeAttributes0 | 10Only used with mode=attrs. When 1, attributes not included in the request payload are preserved. When 0 (default), missing attributes are deleted.
multiUpdatestrueOnly used with mode=attrs and format=json. Enables updating multiple nodes with different attribute values in a single request. The request body must be a JSON array of { where, attrs } objects. See Multi updates.

Upon successful update, the server will return HTTP status 204. If the document does not exist, it will return 404, and if the payload is invalid or the update cannot be applied, it will return 422.

Example: curl command to update a document

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/DOCUMENT_NAME' \\
--header 'Authorization: YOUR_SECRET_FROM_SETTINGS_AREA' \\
--data '@yjsUpdate.binary'

Update via JSON

When updating via JSON, the server computes the difference between the current document state and the provided JSON, then internally calculates the required Yjs update to reach the target state.

To ensure precise updates, especially for node-specific changes, it is recommended to use the nodeAttributeName and nodeAttributeValue parameters. These can be generated by Tiptap's UniqueID Extension or a custom implementation. Note that this only works for top level nodes when using mode=default.

Omitting these parameters may result in overwriting any updates made between fetching the document and issuing the update call. The get document call returns a header x-${fragmentName}-checksum which can be used to detect conflicts by passing it to the update call as ?checksum=${checksum}. If the document has been updated since the last fetch, the update will fail with a 409 Checksum mismatch. status.

Modes

The mode parameter controls how content is applied to the document:

Default mode

Merges nodes from the payload into the document. This is the default behavior when no mode is specified.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "Merged content" }]
    }
  ]
}'

Append mode

Appends nodes to the document's JSON representation without altering existing nodes.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&mode=append' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "This paragraph is appended at the end" }]
    }
  ]
}'

Node mode

Replaces the node matching nodeAttributeName/nodeAttributeValue with the node in the payload.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&mode=node&nodeAttributeName=id&nodeAttributeValue=abc-123' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "paragraph",
  "attrs": { "id": "abc-123" },
  "content": [{ "type": "text", "text": "This replaces the entire matched node" }]
}'

Attrs mode

Replaces attributes of all matched nodes with the request payload (send just the attribute object). See Update only node attrs for details on mergeAttributes.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&mode=attrs&nodeAttributeName=id&nodeAttributeValue=abc-123' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "textAlign": "center",
  "indent": 2
}'

Delete mode

Deletes nodes matching nodeAttributeName/nodeAttributeValue. No payload is needed.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&mode=delete&nodeAttributeName=id&nodeAttributeValue=abc-123' \
--header 'Authorization: YOUR_SECRET'

Useful parameter combinations

Track who made a change

Associate a user ID with the injected content, useful for audit trails and version history.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&user=bot-user-1' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "Injected by bot" }]
    }
  ]
}'

Skip auto versioning

Inject content without creating a new version snapshot.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&skipVersioning=1' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "Silent update" }]
    }
  ]
}'

Update a specific fragment

Target a specific Yjs fragment instead of the default one, or update multiple fragments at once.

# Update a single fragment
curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&fragment=sidebar' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "Sidebar content" }]
    }
  ]
}'
# Update multiple fragments with the same content
curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&fragment=header&fragment=footer' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "Shared content" }]
    }
  ]
}'

Conflict-safe update with checksum

Only apply the update if the document hasn't changed since you last fetched it.

# 1. Fetch the document and note the checksum header (x-default-checksum). The header is present when fetching the document with ?format=json. If you want to get the checksum for a different fragment, send &fragment=customfragmentname
# 2. Use the checksum in the update call
curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&checksum=THE_CHECKSUM_VALUE' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "Only applied if document unchanged" }]
    }
  ]
}'

Merge attributes without deleting existing ones

Update specific attributes on matched nodes while preserving all other existing attributes.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&mode=attrs&nodeAttributeName=id&nodeAttributeValue=abc-123&mergeAttributes=1' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "textAlign": "center"
}'

Full example

Example: Updating a document using JSON

// Define the document name, secret, and application ID
const docName = '' // URI-encoded if necessary
const secret = ''
const appId = ''; // Your document server ID from the Cloud dashboard

// Construct the base URL
const url = `https://${appId}.collab.tiptap.cloud`

// Fetch the current document's JSON representation
const docJson = await axios.get(`${url}/api/documents/${docName}?format=json`, {
    headers: {
    Authorization: secret
  },
})

// Extract the document's JSON content
const tiptapJson = docJson.data
const nodes = tiptapJson.content

// Find and log specific nodes using their unique identifiers
const query = nodes.find(n => n.attrs?.identifier === 'fe5c0789-85d9-4877-a2c3-bccf5d874866').content[0].text
const resultTable = nodes.find(n => n.attrs?.identifier === '246368b6-0746-4ca1-a16f-8d964aff4041')

console.log(`Query: ${query}`)
console.log(JSON.stringify(resultTable.content))

// Append new content to the result table node
resultTable.content.push({
  // New table row content here
  {
    "type": "tableRow",
    "content": [
      {
        "type": "tableCell",
        "attrs": {
          "colspan": 1,
          "rowspan": 1
        },
        "content": [
          {
            "type": "paragraph",
            "attrs": {
              "textAlign": "left"
            },
            "content": [
              {
                "type": "text",
                "text": "Jan"
              }
            ]
          }
        ]
      },
      {
        "type": "tableCell",
        "attrs": {
          "colspan": 1,
          "rowspan": 1
        },
        "content": [
          {
            "type": "paragraph",
            "attrs": {
              "textAlign": "left"
            },
            "content": [
              {
                "type": "text",
                "text": "Thurau"
              }
            ]
          }
        ]
      },
      {
        "type": "tableCell",
        "attrs": {
          "colspan": 1,
          "rowspan": 1
        },
        "content": [
          {
            "type": "paragraph",
            "attrs": {
              "textAlign": "left"
            },
            "content": [
              {
                "type": "text",
                "text": "jan@janthurau.de"
              }
            ]
          }
        ]
      }
    ]
  }
})

// Send the updated JSON back to the server to apply the changes
await axios.patch(`${url}/api/documents/${docName}?format=json`, tiptapJson, {
  headers: {
    Authorization: secret
  }
})

Update only node attrs

If you want to only update attributes of a node, you can use the ?mode=attrs query parameter. This will only update the attributes of the node and not its content. In this mode, the nodeAttributeName and nodeAttributeValue parameters work for any (not just top level) nodes.

By default, all attributes on matched nodes are replaced — attributes not included in the payload are deleted. To preserve existing attributes and only update those specified in the payload, pass ?mergeAttributes=1.

Not specifying a node filter (nodeAttributeName, nodeAttributeValue) will result in all nodes being updated.

curl --location --request PATCH '/api/documents/:identifier?format=json&nodeAttributeName=id&nodeAttributeValue=12&mode=attrs' \
--data '{
  "indent": 12,
  "textAlign": "right"
}'

Multi updates

When using mode=attrs, you can update multiple nodes with different attribute values in a single request by passing multiUpdates=true. Instead of targeting nodes with nodeAttributeName/nodeAttributeValue query parameters, you provide an array of update objects in the request body. Each object specifies a where clause to match nodes and the attrs to apply.

All conditions within a where clause are connected using AND logic — a node must match every specified attribute to be updated.

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&mode=attrs&multiUpdates=true' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '[
  {
    "where": {
      "id": "id123"
    },
    "attrs": {
      "textAlign": "center"
    }
  },
  {
    "where": {
      "name": "customname"
    },
    "attrs": {
      "indent": 2
    }
  }
]'

You can combine multiUpdates with other parameters like user, skipVersioning, fragment, and mergeAttributes:

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc?format=json&mode=attrs&multiUpdates=true&user=bot-user-1&mergeAttributes=1' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '[
  {
    "where": {
      "id": "node-1",
      "type": "heading"
    },
    "attrs": {
      "level": 2
    }
  },
  {
    "where": {
      "id": "node-2"
    },
    "attrs": {
      "textAlign": "right"
    }
  }
]'

Document fields

These endpoints allow you to read and update custom Yjs fields on a document. This is useful when you use custom Yjs types (e.g. Y.getMap('configuration')) and want to get or update values via the API.

Get a document field

GET /api/documents/:identifier/fields?field=:field&type=:type

Returns the current value of a custom Yjs field.

Query parameters

ParameterTypeDefaultDescription
fieldstringThe name of the custom field.
typestringThe Yjs type of the custom field. Supported values: map, array. Passing the wrong type will return incorrect results. Note that calling this endpoint will create the type on the document if it does not exist. Switching the type for the same field name will create unintended side effects.
curl --location 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc/fields?field=configuration&type=map' \
--header 'Authorization: YOUR_SECRET'

Update a document field

PATCH /api/documents/:identifier/fields?field=:field&type=:type
PUT /api/documents/:identifier/fields?field=:field&type=:type

Updates a custom Yjs field on the document.

  • PATCH merges the request body into the existing field values — only the keys you send are updated, existing keys are preserved.
  • PUT replaces the field entirely — keys not present in the request body are removed.

Query parameters

ParameterTypeDefaultDescription
fieldstringThe name of the custom field.
typestringThe Yjs type of the custom field. Only map is supported for updates at the moment.
userstringUser ID to associate with the change.
skipVersioning1If passed, auto versioning won't be triggered by this change.

Example: Merge values with PATCH

curl --location --request PATCH 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc/fields?field=configuration&type=map' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "key": "newValue",
  "array": [1, 2, 3],
  "object": {
    "id": 62,
    "position": ""
  },
  "arrayOfObjects": [
    { "id": 61 }
  ]
}'

Example: Replace all values with PUT

curl --location --request PUT 'https://YOUR_APP_ID.collab.tiptap.cloud/api/documents/my-doc/fields?field=configuration&type=map' \
--header 'Authorization: YOUR_SECRET' \
--header 'Content-Type: application/json' \
--data '{
  "key": "newValue"
}'

Any existing keys not included in the PUT body will be removed from the field.