DingTalk Docs Skill
Responsible for all operations of DingTalk knowledge base and documents, implemented through DingTalk Open Platform API.
Configuration Management (Must Read Before Each Start)
Configuration File Path
~/.dingtalk-skills/config
(retained across sessions, shared by all dingtalk-skills)
Required Configurations for This Skill
| Key | Description | Source |
|---|
| DingTalk application appKey | Open Platform → Application Management → Credential Information |
| DingTalk application appSecret | Same as above |
| Operator unionId | See the "Why operatorId is required" section below |
Startup Process (Before Each Task Execution)
- Read configuration: Check if
~/.dingtalk-skills/config
exists, parse existing key-value pairs
- Identify missing items: Find the keys in the above table that have not been configured yet
- One-time collection: Combine all missing items into one question, do not ask one by one, for example:
The following information is required to proceed (no need to fill in existing information):
- DingTalk application appKey (DingTalk Open Platform → Application Management → Credential Information)
- DingTalk application appSecret
- Your DingTalk userId or unionId (to operate documents as your identity)
- Persistence: Append the values provided by the user to the config file, read directly in the future without asking again
- Execute task: Start operation after the configuration is complete
Note:
/
/
are credentials, it is forbidden to print them completely in the output, only show the first 4 digits +
when confirming.
Authentication
Before each API call, use appKey/appSecret to obtain the current accessToken (valid for 2 hours):
POST https://api.dingtalk.com/v1.0/oauth2/accessToken
Content-Type: application/json
{
"appKey": "<应用 appKey>",
"appSecret": "<应用 appSecret>"
}
Return:
{ "accessToken": "xxx", "expireIn": 7200 }
All subsequent requests need to carry the request header:
x-acs-dingtalk-access-token: <accessToken>
Why is operatorId (unionId) required
DingTalk Open Platform requires all
write operations (create documents, write content, manage members, etc.) must be performed on behalf of a real user identity, not as an anonymous application.
is to declare "who performed this operation" - it will be recorded in the document change history and used for permission verification.
- The value is the operator's (DingTalk cross-organization unique ID), not (only unique within the organization)
- Incorrectly passing userId will cause permission errors or document ownership errors
How to get unionId
Method 1: Known userId → exchange for unionId (most commonly used)
can usually be obtained directly from address book, free login, message callback and other scenarios.
Step 1: Obtain the old version
(different from the new version accessToken, obtained separately here):
GET https://oapi.dingtalk.com/gettoken?appkey=<appKey>&appsecret=<appSecret>
Return:
{ "access_token": "xxx", "expires_in": 7200 }
Step 2: Query user details with userId, extract unionId:
POST https://oapi.dingtalk.com/topapi/v2/user/get?access_token=<旧式token>
Content-Type: application/json
{ "userid": "<钉钉 userId>" }
The returned field
(no underscore) is the unionId.
Note:
(with underscore) may be empty in exclusive DingTalk organizations, please use
.
Method 2: Robot/message scenario
When a user triggers through a DingTalk robot or message, the message body directly contains the
field, which can be directly used as
without additional query.
Method 3: Ask the user directly
If the above methods are not available, ask the user to provide userId or unionId during the initial configuration phase (both can be viewed on the DingTalk personal information page). Write to config after obtaining, no need to obtain repeatedly for subsequent operations.
Core Operations
1. Query user knowledge base list
When the user wants to view the available knowledge bases:
GET https://api.dingtalk.com/v2.0/wiki/workspaces?operatorId=<unionId>&maxResults=20&nextToken=<分页令牌>
x-acs-dingtalk-access-token: <accessToken>
If there is a
, continue to turn pages until there is no
. The
and
in the returned fields are used for subsequent operations.
2. Query knowledge base information
GET https://api.dingtalk.com/v2.0/wiki/workspaces/{workspaceId}?operatorId=<unionId>
x-acs-dingtalk-access-token: <accessToken>
3. Query directory structure (node list)
When the user wants to see what documents/folders are in the knowledge base:
GET https://api.dingtalk.com/v2.0/wiki/nodes?parentNodeId=<nodeId>&operatorId=<unionId>&maxResults=50
x-acs-dingtalk-access-token: <accessToken>
Pass the
of the knowledge base as
to list the top-level content, pass the
of a subfolder to view deeper content.
Each node contains:
,
,
(
/
),
,
,
.
4. Query single node information (by nodeId)
GET https://api.dingtalk.com/v2.0/wiki/nodes/{nodeId}?operatorId=<unionId>
x-acs-dingtalk-access-token: <accessToken>
5. Query node information by document link
When the user provides a document URL (e.g.
https://alidocs.dingtalk.com/i/nodes/Xxx...
):
POST https://api.dingtalk.com/v2.0/wiki/nodes/queryByUrl?operatorId=<unionId>
x-acs-dingtalk-access-token: <accessToken>
Content-Type: application/json
{
"url": "https://alidocs.dingtalk.com/i/nodes/<nodeId>",
"operatorId": "<unionId>"
}
Return node information, where
can be used as
for subsequent content reading.
6. Create document
Create a new document under the specified knowledge base:
POST https://api.dingtalk.com/v1.0/doc/workspaces/{workspaceId}/docs
x-acs-dingtalk-access-token: <accessToken>
Content-Type: application/json
{
"operatorId": "<unionId>",
"docType": "DOC",
"name": "<文档标题>"
}
Return fields:
| Field | Description |
|---|
| Knowledge base node ID (used for deletion) |
| Document content Key (used for content reading and writing, ≠ nodeId) |
| Actual knowledge base ID (may be different from the requested one, must use this value when deleting) |
| Document access link |
is fixed as
(ALIDOC rich text format).
10. Delete document
DELETE https://api.dingtalk.com/v1.0/doc/workspaces/{workspaceId}/docs/{nodeId}?operatorId=<unionId>
x-acs-dingtalk-access-token: <accessToken>
Both
and
are obtained from the response of creating the document. Success returns
.
7. Read document body content (Block structure)
When the user wants to see the content of the document, use
to read the document Block:
GET https://api.dingtalk.com/v1.0/doc/suites/documents/{docKey}/blocks?operatorId=<unionId>
x-acs-dingtalk-access-token: <accessToken>
- Nodes queried through the wiki nodes interface: (same value)
- New documents created through the create document interface: use the field in the response (not )
Return example:
json
{
"result": {
"data": [
{ "blockType": "heading", "heading": { "level": "heading-2", "text": "快速开始" }, "index": 0, "id": "xxx" },
{ "blockType": "paragraph", "paragraph": { "text": "正文内容..." }, "index": 1, "id": "yyy" },
{ "blockType": "unknown", "index": 2, "id": "zzz" }
]
},
"success": true
}
enumeration:
,
,
,
,
,
,
(rich text such as code blocks/images are not parsed yet).
Extract the text of each block and splice them in index order to reconstruct the document text content.
is the
obtained through the wiki nodes interface, they are the same value.
8. Write/overwrite document body content
When the user wants to modify the document content:
POST https://api.dingtalk.com/v1.0/doc/suites/documents/{docKey}/overwriteContent
x-acs-dingtalk-access-token: <accessToken>
Content-Type: application/json
{
"operatorId": "<unionId>",
"docContent": "# 新标题\n\n新的正文内容,支持 Markdown 格式。",
"contentType": "markdown"
}
⚠️ The write operation will overwrite the original content, please confirm with the user or read and backup first before execution.
9. Document member management
Add document member:
POST https://api.dingtalk.com/v1.0/doc/workspaces/{workspaceId}/docs/{nodeId}/members
x-acs-dingtalk-access-token: <accessToken>
Content-Type: application/json
{
"operatorId": "<unionId>",
"members": [
{ "id": "<userId>", "roleType": "editor" }
]
}
options:
(read-only),
(editable)
Typical Scenarios
"Read the content of document X"
- If the user provides a URL, call
POST /v2.0/wiki/nodes/queryByUrl
to get
- Otherwise, traverse to find the target document through
GET /v2.0/wiki/nodes?parentNodeId=...
- Use as , call
GET /v1.0/doc/suites/documents/{docKey}/blocks
- Splice the block text in index order and display it to the user
"Change the content of document X to..."
- Read the original content first, inform the user that it will be overwritten, request confirmation
- Call
POST /v1.0/doc/suites/documents/{docKey}/overwriteContent
, pass in the new content
- Inform the user that the write is successful
"Help me create a document in DingTalk"
- Ask which knowledge base to put it in (list knowledge bases or let the user say the name)
- Find the corresponding through
GET /v2.0/wiki/workspaces
- Call
POST /v1.0/doc/workspaces/{workspaceId}/docs
,
- Return the document link to the user
"View the documents under knowledge base X"
- Find and through
GET /v2.0/wiki/workspaces
- Call
GET /v2.0/wiki/nodes?parentNodeId={rootNodeId}&operatorId=...
- Organize into a directory tree for display
"Add user xxx to document Y"
- Confirm the of the document and the it belongs to
- Call
POST /v1.0/doc/workspaces/{workspaceId}/docs/{nodeId}/members
, specify
Error Handling
| HTTP Status Code | Error Code | Meaning | Handling Method |
|---|
| 400 | | operatorId not passed | Supplement operatorId (unionId) |
| 400 | | Parameter type error | operatorId must be unionId, not userId |
| 401 | — | Token expired | Re-obtain accessToken and retry |
| 403 | Forbidden.AccessDenied.AccessTokenPermissionDenied
| Application lacks permission | is included in the error message, prompt the user to activate the corresponding permission on the open platform |
| 404 | | Interface path does not exist | Check whether the version number (v1.0/v2.0) and path are correct |
| 429 | — | Rate limit triggered | Wait 1 second and retry |
When an error occurs, display the
and
in the response body to the user to assist in troubleshooting.
Required Application Permissions
| Function | Permission scope |
|---|
| Query knowledge base/nodes | |
| Read document body | |
| Write document body | |
| Create/delete documents | |
| Query user unionId (obtain operatorId) | |