Skip to main content

Write content

How to write Markdown content into a DingTalk Docs document?

  • Option 1: Insert content (append without affecting existing content) Call the Insert content API to insert Markdown content at a specified location in the document:
    curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{documentId}/content?operatorId={operatorId}' \
    --header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
    --header 'Content-Type: application/json' \
    --data '{
      "content": {
        "type": "markdown",
        "content": "# Heading 1\n\nThis is a paragraph of body content."
      }
    }'
    
  • Option 2: Overwrite the document (clear and rewrite) Call the Overwrite document (App authorization) API to overwrite the entire document content in Markdown format:
    curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/overwriteContent?operatorId={operatorId}' \
    --header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
    --header 'Content-Type: application/json' \
    --data '{
      "content": "# Document title\n\nBody content.",
      "dataType": "markdown"
    }'
    
    Overwriting clears all existing content in the document. This is a destructive action, so use it with caution. To append content only, use the Insert content API instead.

Block element operations

How to insert a paragraph with content

Call the Insert block element API to insert a paragraph block into the document, and use the children field to specify the inline elements within the paragraph:
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{dentryUuid}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "paragraph",
    "paragraph": {},
    "children": [
      {
        "text": "This is a bold red text",
        "bold": true,
        "color": "#FF5733"
      },
      {
        "elementType": "sticker",
        "properties": { "code": "大笑"  // Laugh }
      }
    ]
  }
}'
If the call succeeded, the response is in the following format:
{
  "result": {
    "data": {
      "paragraph": { "text": "This is a bold red text" },
      "blockType": "paragraph",
      "index": 0,
      "id": "......"
    }
  },
  "success": true
}
The paragraph object cannot be omitted. Even if the paragraph has no special attributes, pass an empty object {}.

How to insert a block element at a specific location (not at the end)

When calling the Insert block element API, specify the target location with blockId or index, and use the where parameter to control whether to insert before or after the target:
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "paragraph",
    "paragraph": {}
  },
  "blockId": "lc4si5p3n84zwqxxx",
  "where": "before"
}'
ParameterDescription
blockIdThe unique identifier of the target block. The new block is inserted before or after this block.
indexWhen blockId is not provided, the index-th top-level block in the document is used as the target location (starting from 0).
where"before" inserts before the target location; "after" inserts after it (default: "after").

How to insert a heading

Call the Insert block element API. Set blockType to heading and use level in the heading object to specify the heading level (1–6):
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "heading",
    "heading": {
      "level": 2,
      "text": "This is a Heading 2"
    }
  }
}'
If the call succeeded, the response is in the following format:
{
  "success": true
}
Mapping between heading.level and heading levels:
levelHeading
1Heading 1 (H1)
2Heading 2 (H2)
3Heading 3 (H3)
4Heading 4 (H4)
5Heading 5 (H5)
6Heading 6 (H6)

How to insert a Quote block

Call the Insert block element API. Set blockType to blockquote and pass the quote content in the blockquote object:
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "blockquote",
    "blockquote": {
      "text": "This is a piece of quoted content"
    }
  }
}'
If the call succeeded, the response is in the following format:
{
  "result": {
    "data": {
      "blockType": "blockquote",
      "index": 4,
      "id": "......"
    }
  },
  "success": true
}

How to insert a Highlight block with a nested paragraph

The children of a Highlight block must be an array of BlockElement. When calling the Insert block element API, pass the child paragraph in children:
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "callout",
    "callout": {
      "sticker": "灯泡",  // Lightbulb
      "showstk": true,
      "bgcolor": "#FFF9C4",
      "border": "#FFD700"
    },
    "children": [
      {
        "blockType": "paragraph",
        "paragraph": { "text": "This is the paragraph content inside the Highlight block" }
      }
    ]
  }
}'
Different block element types accept different children types. The children of a paragraph block can only be inline elements, while the children of a Highlight block can only be block elements.

How to insert columns

Call the Insert block element API. Set blockType to columns, use columns.size to specify the number of columns, and pass the block element content for each column in children:
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "columns",
    "columns": {
      "size": 2,
      "noFill": false
    },
    "children": [
      {
        "blockType": "paragraph",
        "paragraph": { "text": "Left column content" }
      },
      {
        "blockType": "paragraph",
        "paragraph": { "text": "Right column content" }
      }
    ]
  }
}'
If the call succeeded, the response is in the following format:
{
  "result": {
    "data": {
      "columns": { "size": 2 },
      "blockType": "columns",
      "index": 7,
      "id": "......"
    }
  },
  "success": true
}
Fields of the columns object:
FieldTypeDescription
sizeNumberNumber of columns.
noFillBooleanWhether to automatically fill the background color. Default: false.
The children of columns must be a BlockElement array, not inline elements.

How to insert a Numbered List

Call the Insert block element API. Set blockType to orderedList, pass the list attributes in the orderedList object, and pass the list item text in children:
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "orderedList",
    "orderedList": {
      "list": {
        "listId": "my-ordered-list-001",
        "level": 0,
        "listStyleType": "decimal",
        "listStyle": {
          "format": "decimal",
          "text": "%1.",
          "align": "left"
        }
      }
    },
    "children": [
      { "text": "First item of the Numbered List" }
    ]
  }
}'
If the call succeeded, the response is in the following format:
{
  "result": {
    "data": {
      "blockType": "orderedList",
      "index": 6,
      "id": "......"
    }
  },
  "success": true
}
Common fields of the list object:
FieldTypeDescription
listIdStringThe unique identifier of the list. Multiple list items in the same list should share the same listId.
levelNumberList indent tier, starting from 0.
listStyleTypeStringList style type. Use "decimal" for a Numbered List.

How to insert a Bulleted List

Call the Insert block element API. Set blockType to unorderedList, pass the list attributes in the unorderedList object, and pass the list item text in children:
curl --location --request POST 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
  "element": {
    "blockType": "unorderedList",
    "unorderedList": {
      "list": {
        "listId": "my-unordered-list-001",
        "level": 0,
        "listStyleType": "disc",
        "listStyle": {
          "format": "disc",
          "text": "%1",
          "align": "left"
        }
      }
    },
    "children": [
      { "text": "First item of the Bulleted List" }
    ]
  }
}'
If the call succeeded, the response is in the following format:
{
  "result": {
    "data": {
      "blockType": "unorderedList",
      "index": 8,
      "id": "......"
    }
  },
  "success": true
}
The listId of a Numbered List or Bulleted List associates multiple list items with the same list. To insert multiple items belonging to the same list, use the same listId for each item. You can insert all items in one call using the BatchOperate API.

Query operations

How to get the blockId of all block elements in a document?

Call the Query block element API to retrieve the list of top-level block elements under the document’s root node. Each element includes its id (the blockId):
curl --location --request GET 'https://api.dingtalk.io/v1.0/doc/suites/documents/{docKey}/blocks?operatorId={operatorId}' \
--header 'x-acs-dingtalk-access-token: {ACCESS_TOKEN}'
If the call succeeded, the response is in the following format:
{
  "success": true,
  "result": {
    "data": [
      {
        "heading": { "level": "heading-1", "text": "Document title" },
        "blockType": "heading",
        "index": 0,
        "id": "......"
      },
      {
        "paragraph": { "text": "Body content." },
        "blockType": "paragraph",
        "index": 1,
        "id": "......"
      }
    ]
  }
}
The Query block element API currently only supports querying top-level block elements under the document’s root node. Recursive queries on child blocks nested inside containers such as Highlight blocks are not supported.