DingTalk Wiki CDC (Beta)

Updated at:

This topic describes how to use the DingTalk CDC (dingtalk-cdc) connector.

Background Information

Overview

The DingTalk CDC connector periodically polls the DingTalk Open Platform API to continuously capture new and updated online documents in DingTalk Wiki workspaces based on document modification time. The connector outputs metadata such as the title, URL, workspace, parent node, and update time of each document, along with the document body in Markdown format. You can also obtain the raw block structure of documents. This connector applies to scenarios such as RAG knowledge base building, document search indexing, and lakehouse content synchronization.

How It Works (Polling)

DingTalk Wiki does not provide a change event stream that can be consumed directly. DingTalk CDC implements full and incremental reads by polling the OpenAPI:

  1. Each workspace is an independent read shard. If workspace-id is not configured, the connector calls the workspace list API at the interval specified by scan.discovery.interval to discover all workspaces visible to the operator. After it is configured, only the specified workspaces are synchronized.

  2. On each pull, the connector traverses the workspace node tree according to scan.discovery.max-depth and scan.discovery.max-nodes, filters DingTalk online document nodes (type=FILE and category=ALIDOC), and generates the cursor position for this pull based on document modification time.

  3. Documents after the cursor are sorted by modification time. A single shard outputs at most scan.prefix-size documents per pull. For each changed document, the connector reads its block structure through a consistency check mechanism and renders it into a Markdown body.

  4. When there are no incremental changes, the connector repeats the preceding checks at the interval specified by scan.poll-interval.

Changelog Semantics

The connector outputs a changelog with upsert semantics keyed by the primary key doc_id. The changelog contains INSERT and UPDATE_AFTER records, but does not contain UPDATE_BEFORE:

Scenario

Output

A document read for the first time in the full phase

INSERT

A document whose content or metadata changes in the incremental phase

UPDATE_AFTER

The current implementation does not detect document deletions. After a document is deleted, it no longer appears in the node list, and the connector does not output DELETE events. The corresponding row in the downstream system retains the state of the last synchronization. To clean up residual data, submit a batch job that performs an anti-join between the sink table and the source table on the primary key, and deletes the rows whose primary key no longer exists in the source table.

Supported Capabilities

Category

Details

Supported types

Source table and data ingestion source

Execution mode

Streaming mode

Data format

Fixed schema. Field pruning is not supported.

API types

SQL and data ingestion YAML

Synchronization objects

DingTalk online document nodes in workspaces that the operator has permission to read (node type type=FILE and category=ALIDOC)

Startup mode

initial (full + incremental), snapshot (bounded full only), and latest-offset (incremental only). timestamp is not supported.

Watermark

Not supported

Dimension tables and result tables

Not supported

Prerequisites

Network Requirements

A Flink job needs to access the DingTalk Open Platform API (the default domain is api.dingtalk.com). If the job is deployed in a VPC, make sure that it has Internet access. For more information, see Network connection options in the Realtime Compute for Apache Flink documentation.

Application Creation and API Authorization

Regardless of the startup mode, you must first create an application and complete API authorization on the DingTalk Open Platform.

  1. Log on to the DingTalk Developer Console and create an enterprise internal application. On the Credentials and Basic Information page of the application, obtain the Client ID (AppKey) and Client Secret (AppSecret). The connector uses the AppKey and AppSecret to call POST /v1.0/oauth2/accessToken to obtain the access token of the enterprise internal application and automatically renews the token.

  2. Grant the API permissions required by this connector to the application. In the developer console, go to the Permissions page of the target application, and search for and apply for the permissions listed in the following table. Some permissions require approval by an organization administrator. The connector calls the following DingTalk OpenAPI operations:

API

Purpose

Permission

POST /v1.0/oauth2/accessToken

Obtains the access token of an enterprise internal application.

Basic capability. No additional permission is required.

GET /v2.0/wiki/workspaces

Lists the workspaces visible to the operator.

Workspace read permission

GET /v2.0/wiki/nodes?parentNodeId=

Traverses the workspace node tree and lists child nodes.

Workspace node read permission

GET /v2.0/wiki/nodes/{nodeId}

Queries node metadata.

Workspace node read permission

GET /v1.0/doc/suites/documents/{docKey}/blocks

Queries document block elements.

Enterprise storage file read permission

Permission names are subject to the official documentation of the DingTalk Open Platform. The following table summarizes the required permissions:

Capability

API

Required permission

Required

Obtain an access token

oauth2/accessToken

No additional permission is required.

Yes

Read the workspace list

wiki/v2.0/wiki/workspaces

Workspace read permission

Yes

Read node lists and node metadata

wiki/v2.0/wiki/nodes

Workspace node read permission

Yes

Read document block content

doc/v1.0/doc/suites/documents/{docKey}/blocks

Enterprise storage file read permission

Yes

Operator and Workspace Data Authorization

Set operator-id to the Union ID of an enterprise member. You can obtain the Union ID by calling the Query User Details API of the DingTalk Open Platform. All API calls of the connector are made as this operator, and the visible scope is determined by the permissions of the operator:

  • The operator must have at least the View Only permission on the target workspace or document. The View/Download permission or a higher permission is also acceptable.

  • If workspace-id is not configured for the job, the connector can discover only the workspaces visible to the operator.

DingTalk Wiki supports three permission levels: workspace level, folder level, and document level. Documents inherit the permissions of their parent directory by default. The following table describes the permission types and the minimum requirements of this connector:

Permission type

Readable by this connector

Description

View Only

Yes

Meets the minimum read requirement.

View/Download

Yes

Recommended. This avoids additional requirements of some APIs on download capabilities.

Edit

Yes

Exceeds the read requirement. Granting this permission only for synchronization is not recommended.

Manage

Yes

Exceeds the read requirement. Granting this permission only for synchronization is not recommended.

No permission

No

The workspace or document does not appear in the synchronization results.

Authorization methods: The workspace administrator adds the operator in Settings > Members and Permissions of the workspace. Authorization by member, department, or group is supported. You can also grant permissions to the operator in the sharing settings of a single document. New documents inherit workspace permissions by default. After you grant permissions on the whole workspace, newly added documents do not require separate configuration. The connector is a read-only pipeline and does not require any write permission.

Authorization Troubleshooting

The connector does not retry on authorization errors. It fails directly or skips the corresponding document. Troubleshoot based on the following table:

Error code / Symptom

Description

Solution

forbidden.acrossOrg

Cross-organization access is denied.

Make sure that the application, the operator, and the target workspace belong to the same organization. Cross-organization workspaces cannot be synchronized.

orgAuthLevelNotEnough

The organization authentication level does not meet the API requirements.

Complete enterprise verification or upgrade the authentication level in the DingTalk admin console, and then retry.

Insufficient permissions (permission denied errors)

The required permissions are not granted to the application.

Go back to the Permissions page and check whether the workspace read permission, workspace node read permission, and enterprise storage file read permission are all granted.

A workspace or document does not appear in the synchronization results

The operator has no permission to read it.

In Members and Permissions of the workspace, grant the operator the View Only permission or a higher permission.

nodeNotExist (404)

The node has been deleted or the ID is invalid.

The connector automatically skips it. No action is required.

doc key is illegal

The document identifier is invalid.

This is a permanent failure and is not retried. Check the node status or contact DingTalk support.

Limits

  • Only source tables are supported. Dimension tables, result tables, and watermarks are not supported.

  • Only DingTalk online document nodes in workspaces are synchronized (type=FILE and category=ALIDOC). Other objects such as folders, sheets, and uploaded files are skipped.

  • The current implementation does not detect document deletions and does not output DELETE events.

  • The timestamp startup mode is not supported because the DingTalk OpenAPI cannot read historical document content.

  • In a Flink SQL source table, workspace-id supports multiple comma-separated values, but all the workspaces are read into the same source table. To store each workspace in a separate table with an independent schema, use the data ingestion YAML, or create one SQL source table for each workspace.

  • The YAML schema differs from the SQL schema. In the YAML schema, blocks_json is a physical column controlled by scan.block.include-raw-json, and workspace_id is NOT NULL. Choose the corresponding schema definition based on your access method.

  • The incremental pipeline is based on OpenAPI polling and generates continuous API calls. The DingTalk Open Platform imposes quotas on organization-level API calls. The standard edition has a lower quota, and the dedicated edition has a higher quota. If a workspace contains many documents, configure scan.poll-interval, scan.prefix-size, and the rate limiting parameters to control the call cost and the synchronization latency of new content.

  • The process-level rate limiting parameters (scan.discovery/metadata/content.rate-limit.requests-per-second) are shared by all clients that use the same app-key. If multiple jobs share the same application, evaluate the quota as a whole.

  • content is Markdown text rendered from the document block structure. It does not guarantee complete preservation of all rich media and structured elements. Blocks that cannot be rendered are marked with placeholder comments. If you need the raw block structure, declare the blocks_json METADATA column in Flink SQL, or enable scan.block.include-raw-json in the data ingestion YAML to output the blocks_json physical column.

  • Failover recovery may output duplicate INSERT and UPDATE_AFTER records. We recommend that the downstream system perform idempotent writes based on the primary key doc_id.

  • The synchronization scope cannot be narrowed at runtime. If you reduce workspace-id or add scan.document.exclude-node-ids while the job is running, the change affects only the resources that are discovered later. The workspaces or documents that are already discovered are not removed from the current job. To remove them completely, stop the job and restart it without state.

  • Authorization errors (forbidden.acrossOrg, orgAuthLevelNotEnough, invalid docKey, and so on) are permanent failures. The connector does not automatically retry on them. Handle them as described in Authorization Troubleshooting.

SQL

Key Features

  • Fixed-schema source table: outputs the document title, URL, body (Markdown), and metadata, and outputs a changelog with upsert semantics keyed by the primary key doc_id.

  • Startup modes: select the read method by using scan.startup.mode.

Mode

Full read

Incremental read

Behavior on first startup

initial

Yes

Yes

First performs a full read of documents in scope, and then continuously polls for incremental changes.

snapshot

Yes

No

Performs only a full read of documents in scope and ends after completion.

latest-offset

No

Yes

Processes only document changes that occur after the job starts.

  • Raw block structure output: outputs the JSON text of the raw document block structure through the blocks_json METADATA column. You must also enable scan.block.include-raw-json.

Syntax

The Flink SQL DDL must declare all seven physical fields listed in the following table. The field order, names, and case must match exactly. Field names are case-sensitive. You must also declare PRIMARY KEY (doc_id) NOT ENFORCED.

DDL field

Type

Description

doc_id

STRING NOT NULL

The document node identifier. The primary key of the source table.

workspace_id

STRING

The ID of the workspace to which the document belongs.

parent_node_id

STRING

The parent node ID of the document in the workspace node tree.

title

STRING

The document title.

url

STRING

The URL of the document.

content

STRING

The document body. Markdown text rendered from the document block structure.

modified_time

TIMESTAMP_LTZ(3)

The last modification time of the document.

In addition, the DDL can declare the following read-only metadata by using METADATA. Metadata columns do not change the physical schema described above.

Metadata key

Type

Description

blocks_json

STRING

The JSON text of the raw document block structure. You can use it to preserve block-level structure or perform custom parsing. If you declare this column, you must also set 'scan.block.include-raw-json' = 'true'. Both must be enabled or omitted together.

CREATE TEMPORARY TABLE dingtalk_wiki_source (
  doc_id STRING NOT NULL,
  workspace_id STRING,
  parent_node_id STRING,
  title STRING,
  url STRING,
  content STRING,
  modified_time TIMESTAMP_LTZ(3),
  blocks_json STRING METADATA VIRTUAL,
  PRIMARY KEY (doc_id) NOT ENFORCED
) WITH (
  'connector' = 'dingtalk-cdc',
  'object-type' = 'document',
  'app-key' = '<yourAppKey>',
  'app-secret' = '<yourAppSecret>',
  'operator-id' = '<yourOperatorUnionId>',
  'workspace-id' = '<yourWorkspaceId>',
  'scan.startup.mode' = 'initial',
  'scan.block.include-raw-json' = 'true'
);

WITH Parameters

Parameter

Description

Data type

Required

Default value

Remarks

connector

The table type.

String

Yes

None

Fixed value: dingtalk-cdc.

object-type

The type of object to synchronize.

String

Yes

None

Only document is supported.

app-key

The Client ID (AppKey) of the DingTalk enterprise internal application. It is used to obtain the access token.

String

Yes

None

None.

app-secret

The Client Secret (AppSecret) of the DingTalk enterprise internal application.

String

Yes

None

None.

operator-id

The Union ID of the operator. This user must have permission to read the documents to be synchronized.

String

Yes

None

You can obtain it by calling the Query User Details API of the DingTalk Open Platform.

endpoint

The domain of the DingTalk Open Platform OpenAPI.

String

No

https://api.dingtalk.com

None.

workspace-id

Limits the discovery scope to the specified workspaces.

String

No

None

Multiple comma-separated values are supported.

Note

If not configured, all workspaces visible to the operator are automatically discovered. We recommend that you explicitly configure workspace-id.

scan.document.exclude-node-ids

A list of node IDs to exclude.

String

No

None

Comma-separated. These nodes are skipped during both the discovery and pull phases.

scan.discovery.max-depth

The maximum node tree depth allowed for a single workspace polling scan.

Integer

No

100

None.

scan.discovery.max-nodes

The maximum number of nodes allowed to be accessed in a single workspace polling scan.

Integer

No

100000

None.

scan.startup.mode

The startup mode.

String

No

initial

Supports initial, snapshot, and latest-offset. timestamp is not supported.

scan.discovery.interval

The discovery interval of new workspaces.

Duration

No

1min

None.

scan.poll-interval

The polling interval when there are no incremental changes.

Duration

No

10s

Each poll traverses workspace node metadata and reads the body only for the prefix of changed documents sorted by modification time.

scan.prefix-size

The maximum number of documents whose body is output in a single scan of one workspace.

Integer

No

100

None.

scan.document.consistency.max-retries

The maximum number of retries to obtain a document read with stable metadata.

Integer

No

3

Set the value to 0 to disable retries.

scan.document.fetch.max-duration

The maximum duration allowed for one consistency content pull of a single document.

Duration

No

10min

None.

scan.document.max-bytes

The maximum number of bytes allowed for a single document, including the rendered Markdown body.

Long

No

52428800 (50 MiB)

None.

scan.block.fetch-size

The number of top-level blocks requested in a single Block API call.

Integer

No

10

None.

scan.block.max-pages

The maximum number of Block API pages read for a single document.

Integer

No

1000

None.

scan.block.include-raw-json

Specifies whether to output the raw block JSON through the blocks_json read-only metadata column.

Boolean

No

false

You must set this parameter to true if you declare the blocks_json METADATA column.

request.timeout

The timeout period of a single OpenAPI request.

Duration

No

30s

None.

request.max-retries

The maximum number of retries for a failed OpenAPI request.

Integer

No

3

None.

request.retry-after.max-delay

The maximum acceptable Retry-After backoff duration.

Duration

No

60s

Requests are treated as failures when the value is exceeded.

scan.discovery.rate-limit.requests-per-second

The process-level rate limit for discovery requests (listing workspaces and nodes).

Double

No

5

Shared by all clients that use the same app-key.

scan.metadata.rate-limit.requests-per-second

The process-level rate limit for node metadata requests.

Double

No

20

Shared by all clients that use the same app-key.

scan.content.rate-limit.requests-per-second

The process-level rate limit for Block API requests.

Double

No

10

Shared by all clients that use the same app-key.

scan.fetch.rate-limit.requests-per-second

The global pull rate limit.

Double

No

10

Distributed among all subtasks of the source.

Examples

Synchronize workspace documents in full + incremental mode and write them to a Paimon table:

CREATE TEMPORARY TABLE dingtalk_wiki_source (
  doc_id STRING NOT NULL,
  workspace_id STRING,
  parent_node_id STRING,
  title STRING,
  url STRING,
  content STRING,
  modified_time TIMESTAMP_LTZ(3),
  blocks_json STRING METADATA VIRTUAL,
  PRIMARY KEY (doc_id) NOT ENFORCED
) WITH (
  'connector' = 'dingtalk-cdc',
  'object-type' = 'document',
  'app-key' = '<yourAppKey>',
  'app-secret' = '<yourAppSecret>',
  'operator-id' = '<yourOperatorUnionId>',
  'workspace-id' = '<yourWorkspaceId>',
  'scan.startup.mode' = 'initial',
  'scan.block.include-raw-json' = 'true'
);

CREATE TEMPORARY TABLE paimon_sink (
  doc_id STRING,
  workspace_id STRING,
  parent_node_id STRING,
  title STRING,
  url STRING,
  content STRING,
  modified_time TIMESTAMP_LTZ(3)
) WITH (
  'connector' = 'paimon',
  ...
);

INSERT INTO paimon_sink
SELECT doc_id, workspace_id, parent_node_id, title, url, content, modified_time
FROM dingtalk_wiki_source;

snapshot performs only one full read. It is suitable for content migration or one-time export:

CREATE TEMPORARY TABLE dingtalk_wiki_snapshot (
  doc_id STRING NOT NULL,
  workspace_id STRING,
  parent_node_id STRING,
  title STRING,
  url STRING,
  content STRING,
  modified_time TIMESTAMP_LTZ(3),
  PRIMARY KEY (doc_id) NOT ENFORCED
) WITH (
  'connector' = 'dingtalk-cdc',
  'object-type' = 'document',
  'app-key' = '<yourAppKey>',
  'app-secret' = '<yourAppSecret>',
  'operator-id' = '<yourOperatorUnionId>',
  'workspace-id' = '<yourWorkspaceId>',
  'scan.startup.mode' = 'snapshot'
);

To exclude specific documents, add 'scan.document.exclude-node-ids' = '<nodeId1>,<nodeId2>' to the WITH parameters.

CDC YAML Data Ingestion

With the DingTalk CDC YAML connector, you can continuously synchronize the full and incremental changes of online documents in DingTalk Wiki workspaces to a downstream data lake or data warehouse. The type of the data ingestion connector is fixed to dingtalk-cdc.

Key Features

  • Automatic table creation: Each workspace corresponds to a table named <workspaceId>.documents. When the connector discovers a workspace for the first time, it automatically creates the table and synchronizes the schema.

  • Multi-workspace synchronization: workspace-id supports multiple comma-separated values. If not configured, all workspaces visible to the operator are automatically discovered, and each workspace is automatically routed to its own table.

  • Raw block structure output: After you enable scan.block.include-raw-json: true, the output schema contains the blocks_json physical column.

Usage Notes

  • Data ingestion does not support the BATCH execution mode. To export all data, use the snapshot startup mode: the read is bounded, and the job ends automatically after the read completes in a streaming deployment.

  • The full phase (snapshot shards) outputs INSERT events. The incremental phase outputs REPLACE (upsert) events. The downstream system only needs to perform idempotent writes based on the primary key doc_id.

  • Workspaces newly discovered during execution are always read in the initial manner: the current full content is read first, and then subsequent changes are followed.

  • You cannot change scan.block.include-raw-json when a job is restored from a checkpoint or savepoint. Otherwise, the job reports an error and refuses to start.

  • Only DingTalk online document nodes are supported (type=FILE and category=ALIDOC). Other objects are skipped. Document deletions are not detected.

  • The connector continuously calls the DingTalk Open Platform API. Use the rate limiting parameters to control the API call costs. For more information, see the Control Synchronization Speed and API Call Costs example below.

  • app-secret is sensitive information. Reference it by using a project variable, such as ${secret_values.dingtalk_app_secret}, instead of writing plaintext credentials in the job configuration. For more information, see Manage variables.

Syntax

The fixed YAML schema is as follows. The primary key is doc_id. Compared with Flink SQL, the YAML schema outputs blocks_json directly as a physical column instead of a METADATA column, and workspace_id is NOT NULL.

Field

Type

Description

doc_id

STRING NOT NULL

The document node identifier. The primary key.

workspace_id

STRING NOT NULL

The ID of the workspace to which the document belongs.

parent_node_id

STRING

The parent node ID of the document in the workspace node tree.

title

STRING

The document title.

url

STRING

The URL of the document.

content

STRING

The document body. Markdown text rendered from the document block structure.

blocks_json

STRING

The JSON text of the raw document block structure. It is output only when scan.block.include-raw-json: true.

modified_time

TIMESTAMP_LTZ(3)

The last modification time of the document.

Minimal syntax example:

source:
  type: dingtalk-cdc
  name: DingTalk Wiki Source
  object-type: document
  app-key: <yourAppKey>
  app-secret: <yourAppSecret>
  operator-id: <yourOperatorUnionId>
  workspace-id: <yourWorkspaceId>
  scan.startup.mode: initial

route:
  - source-table: <yourWorkspaceId>.documents
    sink-table: dingtalk_wiki.documents

sink:
  type: paimon
  catalog.properties.metastore: rest
  catalog.properties.token.provider: dlf
  catalog.properties.uri: <yourDlfCatalogEndpoint>
  catalog.properties.warehouse: <yourWarehouse>

The preceding example performs a full read of documents in the specified workspace, continuously synchronizes incremental changes, and writes them to Paimon. To synchronize multiple workspaces, set workspace-id to multiple comma-separated IDs. To preserve the raw block structure, add scan.block.include-raw-json: true.

Examples

Each of the following examples is a complete configuration of a data ingestion YAML job. Copy an example and modify it based on your job scenario. For more information about the meaning and the method of obtaining app-key, app-secret, and operator-id, see Prerequisites. The source connector is compatible with all data ingestion sink connectors, such as Paimon, Hologres, and MaxCompute. For the sink configuration, see the documentation of the corresponding connector. All the following examples use Paimon.

Synchronize a Single Workspace (Full + Incremental)

The most basic usage: perform a full read of all documents in the specified workspace, and then continuously synchronize the subsequent changes. The data is written to Paimon (DLF Catalog). This mode is suitable for building a RAG index or a lakehouse content base that must stay consistent with DingTalk Wiki.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator. All API operations are called as this identity, which must have permission to read the workspaces to synchronize
  workspace-id: <yourWorkspaceId>       # Optional. The ID of the workspace to synchronize. If you leave this parameter empty, all workspaces visible to the operator are automatically discovered
  scan.startup.mode: initial            # Optional. The startup mode. Valid values: initial (default, full + incremental), snapshot (full only), and latest-offset (incremental only)

route:
  # The connector automatically creates a source table named <workspaceId>.documents for each workspace,
  # and you can use route to map it to a specific sink table. If you do not configure route, the data is written to the downstream as <workspaceId>.documents.
  - source-table: <yourWorkspaceId>.documents   # The source table. The format is fixed as <workspaceId>.documents
    sink-table: dingtalk_wiki.documents         # The name of the sink table, which can be changed

sink:
  type: paimon                                  # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest            # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server, in the format of http://<region-id>-vpc.dlf.aliyuncs.com
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog
  # (Optional) Enable deletion vectors to improve the read performance of downstream systems
  table.properties.deletion-vectors.enabled: true

pipeline:
  name: DingTalk Wiki to Paimon Pipeline        # The job name

Synchronize Multiple Workspaces, One Sink Table per Workspace

A single job synchronizes multiple workspaces. The connector automatically creates a <workspaceId>.documents sink table for each workspace, which keeps the data of the workspaces separate. This mode is suitable if you want to manage and query the synchronized results by workspace.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator, which must have read permissions on all workspaces to synchronize
  workspace-id: <workspaceId1>,<workspaceId2>   # Optional. The IDs of multiple workspaces, separated by commas (,)
  # (Optional) The discovery interval for new workspaces. Default value: 1min. If workspace-id is configured, this parameter affects only the node scan cycle of the specified workspaces
  scan.discovery.interval: 1min

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog
  table.properties.deletion-vectors.enabled: true     # (Optional) Enable deletion vectors to improve the read performance of downstream systems

# route is not configured: the two workspaces are written to the <workspaceId1>.documents and <workspaceId2>.documents sink tables

pipeline:
  name: DingTalk Wikis to Paimon Pipeline     # The job name
  # (Optional) The parallelism of the job. Each workspace is an independent read shard. When you synchronize multiple workspaces, a higher parallelism speeds up the full read
  parallelism: 2

Merge Multiple Workspaces into One Sink Table

The documents in multiple workspaces share the same schema. You can merge them into a single sink table and query the table as a whole, which is suitable for cross-workspace RAG retrieval. After the merge, use the primary key doc_id of the sink table to ensure idempotence.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator, which must have read permissions on all workspaces to synchronize
  workspace-id: <workspaceId1>,<workspaceId2>   # Optional. The IDs of multiple workspaces, separated by commas (,)

route:
  # Point multiple route rules to the same sink table to merge multiple workspaces.
  # To distinguish the source of each document, keep the workspace_id field in the sink table.
  - source-table: <workspaceId1>.documents      # The source table of the first workspace
    sink-table: dingtalk_wiki.documents         # The sink table that receives the merged data
  - source-table: <workspaceId2>.documents      # The source table of the second workspace
    sink-table: dingtalk_wiki.documents         # Written to the same table as the preceding rule

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog
  table.properties.deletion-vectors.enabled: true     # (Optional) Enable deletion vectors to improve the read performance of downstream systems

pipeline:
  name: Merge DingTalk Wikis to One Paimon Table      # The job name

Automatically Discover All Workspaces

If you leave workspace-id empty, the connector periodically discovers all workspaces that are visible to the operator and automatically synchronizes them. The workspaces that are created later are also added to the synchronization scope in the next discovery cycle. This mode is suitable if the synchronization scope expands along with the workspaces of your organization.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator. The synchronization scope covers the workspaces visible to this operator
  # workspace-id is not configured: all workspaces visible to the operator are automatically discovered
  # (Optional) The discovery interval for new workspaces. Default value: 1min
  scan.discovery.interval: 1min
  # (Optional) The IDs of the document or folder nodes to exclude, separated by commas (,). The excluded nodes are skipped in both the discovery and pull phases
  scan.document.exclude-node-ids: <excludeNodeId1>,<excludeNodeId2>

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog
  table.properties.deletion-vectors.enabled: true     # (Optional) Enable deletion vectors to improve the read performance of downstream systems

pipeline:
  name: Sync All DingTalk Wikis to Paimon       # The job name
  # (Optional) The parallelism of the job. If there are many workspaces, a higher parallelism speeds up the full read
  parallelism: 4

Export All Data at Once (snapshot)

The snapshot startup mode performs a bounded read: it exports the current content of the workspaces to the downstream system in one run, and the job ends automatically when the read completes. This mode is suitable for content migration, one-time backups, and data preparation for offline analysis.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator, which must have permission to read the workspaces to synchronize
  workspace-id: <yourWorkspaceId>       # Optional. The ID of the workspace to export. If you leave this parameter empty, all workspaces visible to the operator are exported
  scan.startup.mode: snapshot           # Full read only. The job ends automatically after the read completes (bounded)

route:
  - source-table: <yourWorkspaceId>.documents   # The source table. The format is fixed as <workspaceId>.documents
    sink-table: dingtalk_wiki.documents         # The name of the sink table, which can be changed

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog

pipeline:
  name: DingTalk Wiki One-Time Export   # The job name

Synchronize Only the Changes After the Job Starts

All existing documents are skipped, and only the documents that are added or modified after the job starts are processed. This mode is suitable if the downstream system already holds complete data and you only need to catch up on the subsequent changes.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator, which must have permission to read the workspaces to synchronize
  workspace-id: <yourWorkspaceId>       # Optional. The ID of the workspace to synchronize. If you leave this parameter empty, all workspaces visible to the operator are automatically discovered
  scan.startup.mode: latest-offset      # Skip the full phase and synchronize only the documents that change after the job starts

route:
  - source-table: <yourWorkspaceId>.documents   # The source table. The format is fixed as <workspaceId>.documents
    sink-table: dingtalk_wiki.documents         # The name of the sink table, which can be changed

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog
  table.properties.deletion-vectors.enabled: true     # (Optional) Enable deletion vectors to improve the read performance of downstream systems

pipeline:
  name: DingTalk Wiki Incremental Sync  # The job name

Preserve the Raw Document Block Structure (RAG Scenarios)

The content field is Markdown text rendered from the document block structure, and it cannot preserve all rich media and structured elements. If your RAG pipeline splits documents by block or parses them in a custom way, such as tables, code blocks, and quotes, enable scan.block.include-raw-json: true. The output schema then appends the blocks_json physical column, which stores the raw block structure of the document as JSON text.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator, which must have permission to read the workspaces to synchronize
  workspace-id: <yourWorkspaceId>       # Optional. The ID of the workspace to synchronize
  scan.startup.mode: initial            # Optional. The startup mode. Default value: initial (full + incremental)
  scan.block.include-raw-json: true     # Optional. Appends the blocks_json physical column to the output schema, which stores the raw block structure of the document as JSON text

route:
  - source-table: <yourWorkspaceId>.documents   # The source table. The format is fixed as <workspaceId>.documents
    sink-table: dingtalk_wiki.documents         # The name of the sink table, which can be changed

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog
  table.properties.deletion-vectors.enabled: true     # (Optional) Enable deletion vectors to improve the read performance of downstream systems

pipeline:
  name: DingTalk Wiki with Raw Blocks   # The job name
Note

You cannot change scan.block.include-raw-json when a job is restored from a checkpoint or savepoint, because this parameter changes the output schema. If you change it, the job reports an error and refuses to start. Decide whether you need this column before you start the job for the first time.

Trim Synchronized Columns (Transform)

The output schema of the connector is fixed. However, you can use Transform rules to trim columns in the synchronization pipeline, so that only the columns that the downstream system requires are written to the result table, which reduces storage costs. The primary key doc_id must be kept in the projection.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator, which must have permission to read the workspaces to synchronize
  workspace-id: <yourWorkspaceId>       # Optional. The ID of the workspace to synchronize

transform:
  - source-table: <yourWorkspaceId>.documents   # The source table of the workspace to which the transform rule applies
    # Projection: keeps only the fields required by the RAG index and drops the columns that are not required, such as parent_node_id. The primary key doc_id must be kept.
    projection: doc_id, workspace_id, title, url, content, modified_time
    description: keep only fields required by the RAG index

route:
  - source-table: <yourWorkspaceId>.documents   # The source table. The format is fixed as <workspaceId>.documents
    sink-table: dingtalk_wiki.documents         # The name of the sink table, which can be changed

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog

pipeline:
  name: DingTalk Wiki to Paimon with Transform  # The job name

Control Synchronization Speed and API Call Costs

The DingTalk Open Platform imposes quotas on organization-level API calls. The standard edition has a lower quota. If your organization has many workspaces or the documents are updated frequently, you can use the following parameters to reduce the call frequency, or to control the API costs within an acceptable synchronization latency for new content. Increasing these parameters instead speeds up the synchronization.

source:
  type: dingtalk-cdc                    # Fixed value. The type of the DingTalk Wiki CDC connector
  name: DingTalk Wiki Source            # The source name
  object-type: document                 # Required. The type of the object to synchronize. Only document is supported
  app-key: <yourAppKey>                 # Required. The Client ID (AppKey) of the DingTalk internal app
  app-secret: <yourAppSecret>           # Required. The Client Secret (AppSecret) of the DingTalk internal app
  operator-id: <yourOperatorUnionId>    # Required. The union ID of the operator, which must have permission to read the workspaces to synchronize
  workspace-id: <yourWorkspaceId>       # Optional. The ID of the workspace to synchronize
  # (Optional) The polling interval when no incremental changes occur. Default value: 10s. A larger value reduces API calls during idle periods, at the cost of a higher synchronization latency for new content
  scan.poll-interval: 30s
  # (Optional) The maximum number of documents whose content a single workspace emits in one scan. Default value: 100. A larger value synchronizes more changed documents in each round
  scan.prefix-size: 100
  # (Optional) The following three rate limiting parameters are process-level and shared by all jobs that use the same app-key. Evaluate them against the API quota of your organization
  # The rate limit on the discovery requests that list workspaces and nodes. Default value: 5 QPS
  scan.discovery.rate-limit.requests-per-second: 5
  # The rate limit on the requests that resolve node metadata. Default value: 20 QPS
  scan.metadata.rate-limit.requests-per-second: 20
  # The rate limit on the Block API requests that read document content. Default value: 10 QPS
  scan.content.rate-limit.requests-per-second: 10

route:
  - source-table: <yourWorkspaceId>.documents   # The source table. The format is fixed as <workspaceId>.documents
    sink-table: dingtalk_wiki.documents         # The name of the sink table, which can be changed

sink:
  type: paimon                          # The type of the sink. This example writes data to Paimon
  catalog.properties.metastore: rest    # The metastore type. Fixed value rest for DLF
  catalog.properties.token.provider: dlf        # The token provider. Fixed value dlf for DLF
  catalog.properties.uri: <yourDlfCatalogEndpoint>    # The endpoint of the DLF Rest Catalog Server
  catalog.properties.warehouse: <yourWarehouse>       # The name of the DLF catalog

pipeline:
  name: DingTalk Wiki Rate-Limited Sync # The job name

Configuration Parameters

Parameter

Description

Data type

Required

Default value

Remarks

type

The connector type.

String

Yes

None

Fixed value: dingtalk-cdc.

object-type

The type of object to synchronize.

String

Yes

None

Only document is supported.

app-key

The Client ID (AppKey) of the DingTalk enterprise internal application.

String

Yes

None

None.

app-secret

The Client Secret (AppSecret) of the DingTalk enterprise internal application.

String

Yes

None

None.

operator-id

The Union ID of the operator. This user must have permission to read the documents to be synchronized.

String

Yes

None

None.

endpoint

The domain of the DingTalk Open Platform OpenAPI.

String

No

https://api.dingtalk.com

None.

workspace-id

A comma-separated list of workspace IDs.

String

No

None

If not configured, all workspaces visible to the operator are automatically discovered.

scan.document.exclude-node-ids

A list of node IDs to exclude.

String

No

None

Comma-separated. These nodes are skipped during both the discovery and pull phases.

scan.discovery.max-depth

The maximum node tree depth allowed for a single workspace polling scan.

Integer

No

100

None.

scan.discovery.max-nodes

The maximum number of nodes allowed to be accessed in a single workspace polling scan.

Integer

No

100000

None.

scan.startup.mode

The startup mode.

String

No

initial

Supports initial, snapshot, and latest-offset. timestamp is not supported.

scan.discovery.interval

The discovery interval of new workspaces.

Duration

No

1min

None.

scan.poll-interval

The polling interval when there are no incremental changes.

Duration

No

10s

None.

scan.prefix-size

The maximum number of documents whose body is output in a single scan of one workspace.

Integer

No

100

None.

scan.document.consistency.max-retries

The maximum number of retries to obtain a document read with stable metadata.

Integer

No

3

Set the value to 0 to disable retries.

scan.document.fetch.max-duration

The maximum duration allowed for one consistency content pull of a single document.

Duration

No

10min

None.

scan.document.max-bytes

The maximum number of bytes allowed for a single document, including the rendered Markdown body.

Long

No

52428800 (50 MiB)

None.

scan.block.fetch-size

The number of top-level blocks requested in a single Block API call.

Integer

No

10

None.

scan.block.max-pages

The maximum number of Block API pages read for a single document.

Integer

No

1000

None.

scan.block.include-raw-json

Specifies whether to include the blocks_json physical column in the output schema.

Boolean

No

false

This configuration cannot be changed when the job is restored.

request.timeout

The timeout period of a single OpenAPI request.

Duration

No

30s

None.

request.max-retries

The maximum number of retries for a failed OpenAPI request.

Integer

No

3

None.

request.retry-after.max-delay

The maximum acceptable Retry-After backoff duration.

Duration

No

60s

Requests are treated as failures when the value is exceeded.

scan.discovery.rate-limit.requests-per-second

The process-level rate limit for discovery requests.

Double

No

5

Shared by all clients that use the same app-key.

scan.metadata.rate-limit.requests-per-second

The process-level rate limit for node metadata requests.

Double

No

20

Shared by all clients that use the same app-key.

scan.content.rate-limit.requests-per-second

The process-level rate limit for Block API requests.

Double

No

10

Shared by all clients that use the same app-key.

scan.fetch.rate-limit.requests-per-second

The global pull rate limit.

Double

No

10

Distributed among all subtasks of the source.