> ## Documentation Index
> Fetch the complete documentation index at: https://dev.marginnote.com.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 获取标签树

> 读整个学习集的标签：实际存储的标签、扁平展开的层级、嵌套的层级树。

`nodes` 是扁平数组，`tree` 是嵌套数组，卡片 id 只挂在扁平的 `nodes` 上。
`directCardCount` 只统计明确存了该条完整路径的卡，`cardCount` 还包含所有下层路径
覆盖到的卡。`derived` 的含义见字段说明。

传入 `withNotes=1` 时，卡片 id 的返回规则见参数说明；数量超出 `noteIdLimit` 时仅标记截断，不自动省略。




## OpenAPI

````yaml /openapi/plugin-api.yaml get /study-sets/{topicid}/hashtags
openapi: 3.1.0
info:
  title: 场景插件 API
  summary: 场景插件在网页面板里可以调用的接口。
  description: >
    场景插件的面板是一个网页。页面里向 `/bridge/v1` 发请求，就能读写 MarginNote 里的数据。

    请求由 MarginNote 处理，与外部命令行工具共用同一套处理代码。外部工具要带令牌，面板不必带。

    面板页面从 `mnpanel://panel/index.html` 加载，因此 `fetch('/bridge/v1' + path)`
    属于同源请求。


    面板调用受这些条件约束：


    - 请求不带令牌，本文件也不声明安全方案。

    - 页面能调用哪些接口，取决于两份名单。模板里的 `plugins` 名单和沉浸态决定面板能不能建好，
      网页面板白名单决定页面能调哪些接口。不在白名单里的请求返回 `403`，
      错误码为 `IN_PROCESS_NOT_ALLOWED`。
    - `GET /capabilities` 里的 `requiresMax` 只约束外部 Agent。面板的请求在 MarginNote 进程内处理，
      不受令牌、订阅状态与跨设备批准的限制，能否调用只看该路径是否在白名单内。
    - 写操作里的 `addon`，MarginNote 会改写为当前面板所属插件的 id；`confirm` 由 MarginNote 补上。
      页面填的值不会生效。

    用 `mn.api(path, opts)` 读取数据。该方法始终将 Response Body 按 JSON 解析，相当于

    `fetch('/bridge/v1' + path, opts).then(r => r.json())`。


    响应的内容不是 JSON 的接口，改用 `fetch`：


    - `GET /guide` 返回 Markdown 正文。

    - `GET /notes/{noteid}/render` 返回卡片长图或 PDF。

    - `GET /documents/{bookmd5}/pages/{index}/content/{contentId}` 返回图片。

    - `GET /bundles/{bundleId}/files` 带 `?path=` 时返回该文件的原始字节。


    调用失败时 Promise 不会进入 reject。MarginNote 把错误对象

    `{"error":{"code":"…","message":"…"}}` 当作 Response Body 返回，因此结果落在 resolve 里。

    判断调用结果看响应里是否带 `error`，写操作另看响应里的 `persisted`。


    接口清单、各项上限与 Request Body 结构随 MarginNote 的版本变化，运行时以 `GET /capabilities` 与

    `GET /guide` 返回的内容为准。
  version: '0.91'
servers: []
security: []
tags:
  - name: 能力与状态
    description: 读取 MarginNote 的能力、版本与当前上下文。调用其他接口之前先读这组。
  - name: 卡片与摘录
    description: 卡片的读取与写入、摘录的创建、批注、标签、元数据与留白。
  - name: 手写会话
    description: 手写层、作答纸、练习准备清单与会话记录的读取与提交。
  - name: 学习集与卡组
    description: 学习集结构、脑图树、子脑图、色板、快照与复习卡组。
  - name: 文档与页面
    description: 文档目录、页文本、页内注释面、摘录清单与同步诊断。
  - name: 导出与 Anki
    description: 文档导出计划、导出文件、Anki 导出能力、作业与产物。
  - name: 查找
    description: 跨库搜索、文件夹列表与学习集列表。
  - name: 界面与模板
    description: 读取当前界面状态与沉浸模板。
  - name: 插件辅助
    description: 面板辅助脚本、已配对设备与本机 helper 信息。
  - name: 任务包与同步诊断
    description: 拆书任务包与旧 CloudKit 同步诊断。
paths:
  /study-sets/{topicid}/hashtags:
    get:
      tags:
        - 学习集与卡组
      summary: 获取标签树
      description: |
        读整个学习集的标签：实际存储的标签、扁平展开的层级、嵌套的层级树。

        `nodes` 是扁平数组，`tree` 是嵌套数组，卡片 id 只挂在扁平的 `nodes` 上。
        `directCardCount` 只统计明确存了该条完整路径的卡，`cardCount` 还包含所有下层路径
        覆盖到的卡。`derived` 的含义见字段说明。

        传入 `withNotes=1` 时，卡片 id 的返回规则见参数说明；数量超出 `noteIdLimit` 时仅标记截断，不自动省略。
      operationId: getStudySetsTopicidHashtags
      parameters:
        - $ref: '#/components/parameters/Topicid'
        - $ref: '#/components/parameters/WithNotes'
      responses:
        '200':
          description: 标签树。卡片 id 只在扁平的 `nodes` 上。
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HashtagsResponse'
              examples:
                recorded:
                  summary: 真机实录（MarginNote 0.61，2026-09-18 录制）
                  value:
                    bridgeApiVersion: '0.61'
                    storedHashtagCount: 2
                    hashtags:
                      - '#FormulaPending'
                      - '#practice/question'
                    title: 理工公式对照材料 · 样例
                    tree:
                      - depth: 1
                        segments:
                          - FormulaPending
                        directCardCount: 1
                        ancestors: []
                        hashtag: '#FormulaPending'
                        cardCount: 1
                        path: FormulaPending
                        derived: false
                        name: FormulaPending
                      - depth: 1
                        segments:
                          - practice
                        directCardCount: 0
                        ancestors: []
                        children:
                          - depth: 2
                            segments:
                              - practice
                              - question
                            directCardCount: 9
                            ancestors:
                              - '#practice'
                            hashtag: '#practice/question'
                            cardCount: 9
                            path: practice/question
                            derived: false
                            name: question
                        hashtag: '#practice'
                        cardCount: 9
                        path: practice
                        derived: true
                        name: practice
                    nodes:
                      - depth: 1
                        segments:
                          - FormulaPending
                        directCardCount: 1
                        ancestors: []
                        hashtag: '#FormulaPending'
                        cardCount: 1
                        path: FormulaPending
                        derived: false
                        name: FormulaPending
                      - depth: 1
                        segments:
                          - practice
                        directCardCount: 0
                        ancestors: []
                        hashtag: '#practice'
                        cardCount: 9
                        path: practice
                        derived: true
                        name: practice
                      - depth: 2
                        segments:
                          - practice
                          - question
                        directCardCount: 9
                        ancestors:
                          - '#practice'
                        hashtag: '#practice/question'
                        cardCount: 9
                        path: practice/question
                        derived: false
                        name: question
                    studySetId: 77012CA0-48E8-4D29-B5F5-1EEA927AE086
                    taggedCardCount: 9
                measured:
                  summary: 实测于 2026-10-07，App 0.91
                  value:
                    withNotes: true
                    storedHashtagCount: 1
                    bridgeApiVersion: '0.91'
                    hashtags:
                      - '#VocabPending'
                    title: The Quiet Case for Walkable Streets
                    tree:
                      - depth: 1
                        segments:
                          - VocabPending
                        directCardCount: 1
                        ancestors: []
                        hashtag: '#VocabPending'
                        cardCount: 1
                        path: VocabPending
                        derived: false
                        name: VocabPending
                    nodes:
                      - depth: 1
                        segments:
                          - VocabPending
                        directCardCount: 1
                        ancestors: []
                        directNoteIds:
                          - A2B013C1-831E-43CD-903F-92AFCA3DFF9D
                        hashtag: '#VocabPending'
                        cardCount: 1
                        path: VocabPending
                        derived: false
                        name: VocabPending
                        noteIds:
                          - A2B013C1-831E-43CD-903F-92AFCA3DFF9D
                    studySetId: 449C1665-E0DD-4A20-9E67-2B0D451F746D
                    taggedCardCount: 1
      x-codeSamples:
        - lang: javascript
          label: 获取标签树与直接关联的卡片
          source: >
            const r = await mn.api('/study-sets/' + topicid +
            '/hashtags?withNotes=1');

            // 卡片 id 在扁平的 nodes 上，嵌套的 tree 里没有

            const node = r.nodes.find(n => n.hashtag === '#VocabPending');

            mn.log(node.directCardCount, node.directNoteIds, node.derived);
components:
  parameters:
    Topicid:
      name: topicid
      in: path
      required: true
      description: >-
        学习集的 topicid。取自 `GET /ui-state` 的 `state.topicid`、`GET
        /library/study-sets`，或 `GET /writing/context` 响应里的 `window.topicid`。
      schema:
        type: string
    WithNotes:
      name: withNotes
      in: query
      required: false
      description: 带 `withNotes=1` 时，一并返回每个标签下直接存有该条完整路径的卡片 id。
      schema:
        type: integer
        enum:
          - 1
  schemas:
    HashtagsResponse:
      type: object
      description: 整个学习集的标签。`nodes` 是扁平的，`tree` 是嵌套的；卡片 id 只出现在扁平的 `nodes` 上。
      properties:
        bridgeApiVersion:
          type: string
        studySetId:
          type: string
        title:
          type: string
        storedHashtagCount:
          type: number
          description: 实际存储的标签数。
        taggedCardCount:
          type: number
        hashtags:
          type: array
          items:
            type: string
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/HashtagNode'
        tree:
          type: array
          items:
            $ref: '#/components/schemas/HashtagNode'
        noteIdsTruncated:
          type: boolean
          description: 为真表示卡片 id 已被截断，数量上限见 `noteIdLimit`。
        noteIdLimit:
          type: number
          description: 卡片 id 的数量上限。
    HashtagNode:
      type: object
      properties:
        hashtag:
          type: string
          description: 完整路径。
        path:
          type: string
        name:
          type: string
        segments:
          type: array
          items:
            type: string
        depth:
          type: number
        ancestors:
          type: array
          items:
            type: string
        directCardCount:
          type: number
          description: 明确存了该条完整路径的卡片数。
        cardCount:
          type: number
          description: 还包含所有下层路径覆盖到的卡片。
        derived:
          type: boolean
          description: 该层只由更深的标签推导出来，自身没有被直接使用。
        children:
          type: array
          description: 只在嵌套的 `tree` 里出现。
          items:
            $ref: '#/components/schemas/HashtagNode'
        directNoteIds:
          type: array
          description: 请求带 `withNotes=1` 时出现。
          items:
            type: string
        noteIds:
          type: array
          description: 请求带 `withNotes=1` 时出现，含下层覆盖到的卡片。
          items:
            type: string

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.