SuperAPI AI Directory

lexiang

Office & productivity

View repository

Updated 10-16 09:18

About this skill

Tencent Lexiang Knowledge Base API

Tencent Lexiang Knowledge Base is an enterprise-level knowledge management platform that provides knowledge bases, team collaboration, document management, AI assistant, and other features.

Data Model

  • Team: Top-level organizational unit; a team can contain multiple knowledge bases (Spaces)
  • Space (Knowledge Base): A container for knowledge, belonging to a team, containing multiple entries (Entry), with root_entry_id as the root node
  • Entry (Item/Knowledge): A content unit in a knowledge base, which can be a page, folder, or file, supporting a tree structure (parent_id)
  • File: An entry of the attachment type, such as PDF, Word, images, etc.

Hierarchical relationship:Team -> Space -> Entry(树形结构,root_entry_id 为根)

URL Rules

When generating a knowledge base link,you must use the lexiangla.com domain + company_from parameter, otherwise the link cannot be opened.

Prohibited formats:

  • https://csig.lexiangla.com/pages/{id}(missing company_from, cannot be opened)
  • https://lexiang.tencent.com/wiki/{id}(internal address, inaccessible externally)

Correct link format:

Resource Type URL Format
Team Homepage https://lexiangla.com/t/{team_id}/spaces?company_from={company_from}
Knowledge Base https://lexiangla.com/spaces/{space_id}?company_from={company_from}
Knowledge Item https://lexiangla.com/pages/{entry_id}?company_from={company_from}

company_from The parameter is the enterprise identifier, and its value differs for different enterprises. It can be extracted from Lexiang links previously shared by the user, or the user can be asked on first use.

Preferentially use the links field in the API response; if the API does not return a complete link, concatenate it according to the above rules (do not forget the company_from parameter)。

Credential Configuration

Required Credentials

Credential Description Required
LEXIANG_APP_KEY Lexiang Open Platform App Key Yes (to obtain Token)
LEXIANG_APP_SECRET Lexiang Open Platform App Secret Yes (to obtain Token)
LEXIANG_STAFF_ID Employee Identity Identifier Yes (required for write operations)

Credential Loading Priority

  1. Cached valid Token(~/.config/lexiang/token, reused directly within the 2-hour validity period, no app_key needed)
  2. Environment Variables(LEXIANG_APP_KEY / LEXIANG_APP_SECRET)
  3. openclaw.json(~/.openclaw/openclaw.json of skills.entries.lexiang.env field)
  4. credentials file(~/.config/lexiang/credentials, JSON format)
  5. Interactive guidance(automatically guides the user for input when stdin is available, and persists it to the credentials file after verification)

Initialization (load credentials + obtain Token)

Execute the scripts/init.sh script to automatically handle credential loading and Token acquisition:

source scripts/init.sh
# 之后可使用 $LEXIANG_TOKEN 和 $LEXIANG_STAFF_ID

On first use, if there are no configured credentials, the script will automatically guide the user to enter the App Key, App Secret, and Staff ID in the terminal, and after verification passes, automatically save them to ~/.config/lexiang/credentials, so there is no need to enter them again later.

Non-interactive environments (such as CI/CD), the script will output clear configuration prompts and format examples to help users manually create configuration files.

Tokens are valid for 2 hours, with a rate limit of 20 requests per 10 minutes. The script will automatically cache to ~/.config/lexiang/token。

Manually configure the credentials file

mkdir -p ~/.config/lexiang
cat > ~/.config/lexiang/credentials << 'EOF'
{
  "app_key": "your_app_key",
  "app_secret": "your_app_secret",
  "staff_id": "your_staff_id"
}
EOF
chmod 600 ~/.config/lexiang/credentials

API Call Basics

Request headers

# 读操作
-H "Authorization: Bearer $LEXIANG_TOKEN"
-H "Content-Type: application/json; charset=utf-8"

# 写操作(额外需要)
-H "x-staff-id: $LEXIANG_STAFF_ID"

Interfaces requiring x-staff-id

All write operations (create/update/delete), AI search/Q&A, permission settings

Format for creating a knowledge node

Use the JSON:API specification format, and specify via relationships the knowledge base and parent node it belongs to:

{
  "data": {
    "type": "kb_entry",
    "attributes": {"entry_type": "page", "name": "标题"},
    "relationships": {
      "space": {"data": {"type": "kb_space", "id": "SPACE_ID"}},
      "parent_entry": {"data": {"type": "kb_entry", "id": "PARENT_ID"}}
    }
  }
}

General limits

  • Rate limit: most interfaces 3000 requests/minute
  • Permission requirements: must be within the AppKey's authorization scope

Core workflow

1. Parse the Lexiang URL

When a user provides a Lexiang link, you can use scripts/parse_url.sh to automatically parse and obtain the detailed information needed by the API:

source scripts/init.sh
source scripts/parse_url.sh "https://lexiangla.com/spaces/{space_id}?company_from=xxx"
# 之后可使用以下环境变量:
# $LEXIANG_PARSED_TYPE       - 资源类型: space / entry / team
# $LEXIANG_PARSED_ID         - 资源 ID
# $LEXIANG_PARSED_SPACE_ID   - 知识库 ID
# $LEXIANG_PARSED_TEAM_ID    - 团队 ID
# $LEXIANG_PARSED_NAME       - 资源名称
# $LEXIANG_PARSED_ROOT_ENTRY_ID - 根节点 ID

Supported URL formats:

URL format Parse result
https://lexiangla.com/spaces/{space_id}?... Knowledge base information (including root_entry_id, team_id)
https://lexiangla.com/pages/{entry_id}?... Document information (automatically look up the knowledge base and team it belongs to)
https://lexiangla.com/t/{team_id}/spaces Team information

For entry-type URLs, the script will look upward through the parent chain to find the root entry, and then look up the knowledge base in reverse via team → spaces. Lookup results are automatically cached to ~/.config/lexiang/space_cache.json。

2. Query knowledge

# 获取团队列表
curl "https://lxapi.lexiangla.com/cgi-bin/v1/kb/teams?limit=20" \
  -H "Authorization: Bearer $LEXIANG_TOKEN"

# 获取知识库列表
curl "https://lxapi.lexiangla.com/cgi-bin/v1/kb/spaces?team_id={team_id}&limit=20" \
  -H "Authorization: Bearer $LEXIANG_TOKEN"

# 获取知识列表
curl "https://lxapi.lexiangla.com/cgi-bin/v1/kb/entries?space_id={space_id}&limit=20" \
  -H "Authorization: Bearer $LEXIANG_TOKEN"

# 获取文档内容(HTML 格式)
curl "https://lxapi.lexiangla.com/cgi-bin/v1/kb/entries/{entry_id}/content?content_type=html" \
  -H "Authorization: Bearer $LEXIANG_TOKEN"

3. Create a document

Comparison of the three methods:

Method Pros Cons Recommended scenario
Upload a Markdown file Simple and efficient Creates a file type, cannot be edited online Archiving, bulk import
Markdown → Online document Preserves formatting + can be edited online Requires a conversion step Preferred when the user requests an editable online document
Manually build with the block interface Precise control over each block Complex, error-prone Programmatically modify existing document content

Method A: Upload a Markdown file(creates a file type, cannot be edited online)

source scripts/init.sh
bash scripts/upload_file.sh ./document.md SPACE_ID [PARENT_ENTRY_ID]

Method B: Markdown → Online document(creates a page type, can be edited online) ⭐ Recommended

Use the scripts/md_to_page.py script to automatically parse Markdown into blocks and write them into an online document:

source scripts/init.sh

# 创建新 page 并写入
python3 scripts/md_to_page.py ./document.md --space-id SPACE_ID --parent-id PARENT_ID --name "文档标题"

# 写入已有 page
python3 scripts/md_to_page.py ./document.md --entry-id ENTRY_ID

# 追加模式(不清空已有内容)
python3 scripts/md_to_page.py ./document.md --entry-id ENTRY_ID --append

Script features:

  • Automatically parses headings, paragraphs, lists, code blocks, quote blocks, horizontal rules, etc.
  • Quote blocks (>) are automatically converted to callout highlight blocks(the API does not support quote, so callout is used to simulate it)
  • Inline styles: bold, italic, inline code, links
  • Automatically submit in batches (each batch ≤20 top-level blocks) to avoid oversized requests
  • Automatically retry block by block on failure
  • When updating an existing page, it is cleared before writing by default(non- --append mode), to avoid duplicate content

Note: The image block cannot be created via API; image references in Markdown will be ignored. If you need images, please insert them manually in the online document.

4. AI Search and Q&A

# AI 搜索
curl -X POST "https://lxapi.lexiangla.com/cgi-bin/v1/ai/search" \
  -H "Authorization: Bearer $LEXIANG_TOKEN" \
  -H "x-staff-id: $LEXIANG_STAFF_ID" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{"query": "搜索关键词"}'

# AI 问答(research=true 使用专业研究模式)
curl -X POST "https://lxapi.lexiangla.com/cgi-bin/v1/ai/qa" \
  -H "Authorization: Bearer $LEXIANG_TOKEN" \
  -H "x-staff-id: $LEXIANG_STAFF_ID" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{"query": "问题内容", "research": false}'

Key considerations for using the block API

For scenarios that require using the online document block API, note the following points (for detailed examples, see references/api-blocks.md):

  1. Creating a new document does not pass parent_block_id: directly insert content into the page root node
  2. List block field names differ from type names:bulleted_list use the bulleted field,numbered_list use the numbered field
  3. Heading block fields must match:h1 use heading1,h2 use heading2, not text
  4. Nested block's children and block_id are declared only on the block itself; do not put them at the top level of the payload: nested blocks (callout/table/toggle, etc.) establish parent-child relationships through the block's own block_id + children field.Do notpass children at the top level of the payload— children at the top level of the payload will cause the API to promote these blocks to the first batch of child nodes at the page root, disrupting the order in the descendant array, causing nested blocks to appear at the beginning of the page (rather than rendering at their actual positions in the document)
  5. quote is not in the list of types supported by the API: the API's valid block_type does not include quote. Markdown blockquotes (>) should be converted to callout(highlight block) to simulate.scripts/md_to_page.py has automatically handled this conversion
  6. Nested types not supported:h1-h5、code、image、attachment、video、divider、mermaid、plantuml
  7. The image block cannot be created via API: the blocks API does not support image block_type, so images cannot currently be inserted into documents via the API. When uploading an MD file containing image references, local image paths will remain as-is (to be updated after the API supports it)
  8. Use for folder type folder: when creating a folder, entry_type must use folder(not directory)
  9. The name of a file type must include an extension: e.g. 文档标题.md、image.png
  10. When there are many blocks, they must be submitted in batches: it is recommended to have no more than 20 top-level blocks per batch.scripts/md_to_page.py has built-in batching logic
  11. descendant The API uses append semantics, not overwrite:POST blocks/descendant will append new blocks at the end of the page,will notclear existing content. When updating an existing page, you must first retrieve all block IDs and delete them one by one (DELETE blocks/{block_id}), otherwise each write will produce duplicate content.scripts/md_to_page.py In non- --append mode, built-in clearing logic is already included

Troubleshooting common errors

Error message Cause Solution
必须指定员工账号 Missing x-staff-id Add -H "x-staff-id: $LEXIANG_STAFF_ID"
data.attributes.entry_type 不能为空 Malformed request Use the JSON:API specification format
entry_type Invalid value Used directory Change to folder
content_type 不能为空 Missing parameter Add ?content_type=html
List content is empty Incorrect field name For unordered lists use bulleted, for ordered lists use numbered
Nested block creation failed Missing association Ensure children + block_id are paired
file name is missing an extension name field has no extension Add .md、.png and other extensions
Upload API 404 Legacy path Use /v1/kb/files/upload-params
Property setting silently fails value passed the option key instead of the text value In the value array, pass the option'sdisplay text(e.g. "互联网参考"), not the key (e.g. c0jp3b6qyh). Passing the key returns 200 but the value is empty
Property setting 400 error Incorrect request body format Must use JSON:API format:{"data":{"type":"kb_entry","attributes":{"属性ID":{"value":["选项文本"]}}}}
PATCH rename 404 File type entries do not support PATCH rename After a file type entry is created, its name cannot be modified through the API; the correct file name must be used at upload time (upload_file.sh will use the file's local file name)
Duplicate page content POST blocks/descendant has append semantics Before updating a page, you must first clear the existing blocks (GET children → DELETE one by one), or use md_to_page.py 's default mode (automatically clears then writes). Only use --append
Nested blocks (callout/table) end up at the beginning of the page Passed children parameter at the top level of the payload Do notpass childrenat the top level of the payload. The parent-child relationship of nested blocks is established only through the block's own block_id + children at the top level of the payload children will cause the API to promote the declared blocks to the first batch of child nodes at the page root, disrupting the order

Experience case

Cross-space knowledge base migration

Scenario: Migrate all content (folder structure + files + online documents) of one knowledge base (Space) to another knowledge base.

Core challenge: LXP API does not havea native move/copy API; you must manually traverse → rebuild the directory → download/upload.

Migration process:

  1. Traverse the source knowledge base directory structure:GET /kb/entries?space_id=SOURCE&limit=50, obtaining folders and sub-entries layer by layer
  2. Create folders with the same names in the target knowledge base:POST /kb/entries,entry_type: "folder"
  3. Handle entries separately by type:
    • file type: obtain the download link from data.links.download → download locally → re-upload to the target folder through the three-step upload process (obtain credentials → upload to COS → create entry)
    • page type: obtain HTML through the content API → parse into blocks → write to the target page

Pitfall log:

Issue Cause Solution
page content is empty No content blocks were written after creating the page entry.POST /kb/entries only creates an empty page shell; content must be written separately through the blocks API Use GET /kb/entries/{id}/content?content_type=html to obtain the source page HTML, parse it, then use POST /kb/page/entries/{id}/blocks/descendant to write to the target page
Upload credential parsing error Bucket/Region in the response's options level, rather than the object level;key/state/auth at the object level Upload credential response structure:options.Bucket、options.Region、object.key、object.state、object.auth.Authorization、object.auth.XCosSecurityToken
Wrong file download link retrieved The file download link is in data.links.download, rather than included in Prefer to get it from data.links.download ,included the kb_file link in as a fallback
Filename missing extension Entry name field does not necessarily contain an extension Parse the extension from the download URL's path (os.path.splitext(urlparse(url).path)[1]), and append it to the end of the filename

Key points for HTML → Blocks conversion:

Lexiang online documents' HTML uses lx-* class names to identify block types (such as <p class="lx-p">、<h2 class="lx-h2">). When converting:

  • Paragraph (p)→ {"block_type": "p", "text": {"elements": [...]}}
  • Heading (h1-h5)→ {"block_type": "h2", "heading2": {"elements": [...]}}(note that the field name is heading{N} not text)
  • Inline styles are mapped to <b>/<i>/<u>/<span style="..."> via text_style
  • Empty paragraphs can be skipped and not written
  • When there are many blocks, write them in batches (recommended ≤ 20 blocks per batch)

Custom attribute settings

Scenario: Set custom attributes for knowledge entries (such as "content nature" and "content source") to make it easier for the Agent to filter and retrieve by type.

Correct API call method:

# 获取条目当前属性值
curl "https://lxapi.lexiangla.com/cgi-bin/v1/kb/entries/{entry_id}/properties/values" \
  -H "Authorization: Bearer $LEXIANG_TOKEN"

# 设置属性值(必须使用 JSON:API 格式)
curl -X PUT "https://lxapi.lexiangla.com/cgi-bin/v1/kb/entries/{entry_id}/properties/values" \
  -H "Authorization: Bearer $LEXIANG_TOKEN" \
  -H "x-staff-id: $LEXIANG_STAFF_ID" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{"data":{"type":"kb_entry","attributes":{"属性ID":{"value":["选项显示文本"]}}}}'

Pitfall log:

Problem Cause Solution
PUT returns 200 but the attribute value is empty value passed the option's key (such as c0jp3b6qyh) Change to passing the option'sdisplay text(such as "互联网参考")
PUT returns 400 data/data.attributes 不能为空 The request body used the {"properties": [...]} format Must use JSON:API format:{"data":{"type":"kb_entry","attributes":{...}}}
Difference between attribute ID and option key The attribute ID is the UUID of the attribute itself, and the option key is the identifier of the option GET /kb/properties/{id} Get attribute details and option list

Online document updates cause duplicate content (severe)

Scenario: When using md_to_page.py --entry-id to update an existing online document, the page content is duplicated 2~4 times.

Root cause analysis:

The Blocks API's POST /kb/page/entries/{id}/blocks/descendant isappendsemantics—it does not overwrite existing content, but appends new blocks at the end of the page. The script initially had no clearing logic, so each run appended the full content to the existing page. Combined with retries after partial failures in the first write, the page eventually accumulated 580 blocks (normally it should be ~147).

Timeline of when the problem surfaced:

  1. First write: some blocks failed because the quote type was not supported → retried after fixing
  2. Second write: all succeeded, but at this point the content was already duplicated
  3. Several more writes were triggered during subsequent debugging → the content expanded to 4 times

Fix measures:

  1. md_to_page.py Added clear_page_blocks(): in non- --append mode, delete all existing root blocks on the page before writing
  2. Use parallel deletion(ThreadPoolExecutor(max_workers=10)) + multiple rounds of looping, ensuring that even a large number of blocks can be cleared within a reasonable time
  3. The API return format differs from expectations(see the table below for pitfalls)

Pitfall Log:

Problem Cause Solution
Updating an existing page causes duplicate content Blocks descendant The API has append semantics and will not overwrite existing content Before updating, first call GET blocks/children to get all block IDs, then DELETE each one to clear it, and then write the new content.--append The parameter skips clearing
When clearing, str has no attribute get blocks/children the API returns {"data": {"blocks": [...]}} instead of {"data": [...]} Use resp["data"]["blocks"] to get the block list, not resp["data"]
The block ID field name is wrong The unique identifier field of a block is block_id, not id When deleting, use block["block_id"]
Deleting one by one is too slow (580 blocks timed out) Serial HTTP requests, about 200ms each Switch to ThreadPoolExecutor(max_workers=10) parallel deletion, looping for multiple rounds until cleared
Nested blocks (callout) end up at the very beginning of the page The payload passed children: ["callout-xxx"]at the top level, and the API promoted it to the first batch of child nodes at the page root Do notpass childrenat the top level of the payload. The parent-child relationship of nested blocks only needs to be established through the block's own block_id + children , and the API will render in the order of the descendant array

Core Lessons:

Operations on remote APIs must be idempotent. Before writing content, if it is not append mode, you must first confirm whether the target is empty—you cannot assume the API will automatically overwrite. This kind of problem does not occur in local file operations (write defaults to overwrite), but it is extremely common in API scenarios.

When integrating a new API for the first time, you must verify: Is the interface's semantics "overwrite" or "append"? Will retries after failure produce side effects?

The semantics of API parameters cannot be taken for granted。descendant In the request body, the children parameter appears to be used to declare nested block relationships, but its actual meaning is "specify the first-level child blocks of the page root node"—it changes the rendering position of blocks. The parent-child relationship of nested blocks (callout/table) should only be declared on the block itself (block_id + children), and does not need and should not be repeatedly declared at the top level of the payload.When API behavior does not meet expectations, first conduct small-scale controlled experiments (passing/not passing a certain parameter), then apply it to the full data。

Detailed API Reference

Consult the following reference files as needed to obtain complete interface documentation:

File Content Search keywords
references/api-contact.md Contacts management (member/department CRUD) contact, user, department, staff
references/api-team-space.md Team and knowledge base management team, space, permissions, subject
references/api-entries.md Knowledge node CRUD and permissions entry, entries, page, directory, file
references/api-blocks.md Online document block interface (create/edit block content) block, descendant, paragraph, table, list
references/api-other.md Tasks/attributes/logs/AI/assets/export/SSO task, property, log, ai, search, qa, upload, sso

HTTP error codes

Status code Description
200/201 Success
204 Deleted successfully
400 Invalid request parameters
401 Token is invalid or expired
403 No permission
404 Resource does not exist
429 Rate limit exceeded