客户端 API 使用说明

一、适用场景

客户端 API 用于在局域网内把记乎桌面版接入自动化工具、脚本、内部系统或自定义制卡流程。外部程序可以通过 HTTP 管理当前桌面版中的牌组、目录、模板、卡片和资源。

这是桌面版的本地接口,不是记乎云端开放 API。接口实际操作当前电脑上的本地数据;需要将数据同步到云端时,请显式调用同步接口。

当前可用范围

客户端 API 当前仅在 Preview 或开发构建中显示,并要求有效的 PLUS 会员。正式版没有设置入口。

二、启用方式

  1. 打开记乎桌面版设置。
  2. 进入“客户端 API”。
  3. 开启“启用客户端 API”。该功能需要 PLUS 会员。
  4. 复制页面显示的 API 地址、访问秘钥,或直接复制 OpenAPI 地址。

关闭开关后,API 服务会停止监听;重置访问秘钥后,旧秘钥立即失效。桌面版退出时也会停止 API 服务。

三、连接与鉴权

设置页显示的地址是完整的局域网访问地址,例如:

http://192.168.1.8:18080

所有需要鉴权的请求可选择以下任一种方式传递秘钥。建议使用请求头,避免秘钥出现在代理或访问日志中:

X-API-SECRET: <访问秘钥>

或

GET /decks/all?secret=<访问秘钥>
接口访问秘钥桌面版登录状态
GET /_check不需要不需要
GET /openapi.json不需要不需要
GET /app/info需要不需要
其余接口需要需要已登录的桌面版会话

/_check 只用于判断 HTTP 服务是否存活,不代表桌面版已登录或牌组可用。/openapi.json 返回当前版本的机器可读接口描述。

四、通用约定

  • JSON 请求使用 Content-Type: application/json;资源上传使用 Content-Type: application/octet-stream
  • JSON 响应中的嵌套字段统一使用 snake_case,例如 deck_idcategory_sncreated_at。卡片兼容字段 _usn_synced 保留原名称。
  • 返回实体的接口返回 JSON;删除和同步等无实体返回的成功响应为 text/plainok
  • 路径中的 deckId 为正整数;categorySNtemplateSNcardSN 和资源名称包含特殊字符时必须进行 URL 编码。
  • JSON 请求正文上限为 42 MB,资源上传正文上限为 100 MB。超过上限返回 413 PAYLOAD_TOO_LARGE

五、系统接口

方法和路径说明成功响应
GET /_check检查服务是否正在监听文本 ok
GET /openapi.json获取 OpenAPI 3.1 接口描述OpenAPI JSON
GET /app/info获取桌面版和操作系统信息应用信息对象
POST /sync同步全部本地牌组文本 ok

/app/info 返回字段包括 app_typeapp_versionapp_build_numberos_typeos_versionos_arch。该接口只需要 API 秘钥,不要求登录。

六、牌组接口

方法和路径请求参数返回
GET /decks/cloud云端牌组数组
GET /decks/all本地牌组数组
POST /decks/createJSON:nametypethumb新建牌组
GET /decks/{deckId}/info路径:deckId牌组对象
POST /decks/{deckId}/fetch路径:deckId下载后的牌组结果
POST /decks/{deckId}/updateJSON:namethumb更新后的牌组
POST /decks/{deckId}/delete可选查询参数 completelyDelete=1文本 ok
POST /decks/{deckId}/sync路径:deckId文本 ok

创建牌组示例:

POST /decks/create
Content-Type: application/json
X-API-SECRET: <访问秘钥>

{
  "name": "英语词汇",
  "type": 2,
  "thumb": null
}

type 兼容旧客户端编号:0 普通牌组、1 笔记本、2 词汇、6 混合、7 题库。未填写时按普通牌组处理;其他值会返回 400 INVALID_ARGUMENT。删除接口默认只删除本机牌组,带 completelyDelete=1 时执行彻底删除,请确认数据备份后再使用。

牌组对象通常包含 idtypenamethumb_urldescriptionthemepkg_idpkg_versionstandaloneenabledtotal_cardscreated_atupdated_at。具体字段以当前版本的 /openapi.json 和实际响应为准。

七、目录接口

方法和路径请求参数返回
GET /decks/{deckId}/categories/list路径:deckId目录数组(已展开,不含 children
POST /decks/{deckId}/categories/createJSON:name,可选 descriptionparentSN新建目录
POST /decks/{deckId}/categories/{categorySN}/updateJSON 或查询参数:name更新后的目录
POST /decks/{deckId}/categories/{categorySN}/delete文本 ok

创建子目录示例:

POST /decks/42/categories/create
{
  "name": "第四级",
  "description": "可选说明",
  "parentSN": "category-parent-sn"
}

也可以用 parentcategory 传目录名称,桌面版会在当前牌组中查找同名目录;建议优先使用稳定的 parentSN。列表中的每个目录包含 idsndeck_idparent_snnamedescriptionlevelordercards_numis_locked、时间和同步字段。

通过此兼容接口删除目录时不会递归删除子目录或卡片;非空目录(包含子目录或卡片)会返回 400 CATEGORY_NOT_EMPTY。需要删除前请先确认目录内容。

八、模板接口

方法和路径请求参数返回
GET /decks/{deckId}/templates/list路径:deckId模板数组
POST /decks/{deckId}/templates/createJSON:typenamefieldsstyleoptions;可选 description新建模板
GET /decks/{deckId}/templates/{templateSN}/info路径:deckIdtemplateSN模板对象
POST /decks/{deckId}/templates/{templateSN}/update可更新 namedescriptionfieldsstyleoptions 等字段更新后的模板
POST /decks/{deckId}/templates/{templateSN}/delete文本 ok

模板创建示例:

POST /decks/42/templates/create
{
  "type": 0,
  "name": "问答模板",
  "description": "正面和背面",
  "fields": [
    {"name": "front", "data_type": 0, "required": true},
    {"name": "back", "data_type": 1, "required": true}
  ],
  "style": {"front": "front", "back": "back"},
  "options": {}
}

fieldsstyleoptions 会按模板原样传递。更新请求的牌组 ID 和模板 SN 以路径为准,即使正文中带有同名字段也不会覆盖路径身份。模板对象还可能包含 prototype_idis_defaultcards_numusnsynced_at 等字段。

九、卡片接口

方法和路径请求参数返回
POST /decks/{deckId}/cards/searchJSON:可选 querylimit兼容格式卡片数组
POST /decks/{deckId}/cards/createJSON:styledata;可选标题、模板、目录、选项和顺序新建或处理冲突后的卡片
GET /decks/{deckId}/cards/{cardSN}/info路径:deckIdcardSN兼容格式卡片
POST /decks/{deckId}/cards/{cardSN}/update可选 titledataoptionsorder、目录更新后的兼容格式卡片
POST /decks/{deckId}/cards/{cardSN}/delete文本 ok

卡片样式编号

style含义
0基础卡(basic)
1简答卡(simple)
10笔记卡(note)
30单词卡(word)
31扩展单词卡(word-extended)
60问答卡(question)
61选择题(choice)
62判断题(judgement)

创建卡片示例:

POST /decks/42/cards/create
{
  "style": 1,
  "title": "光合作用",
  "templateSN": "template-sn",
  "categorySN": "category-sn",
  "order": 10,
  "data": {
    "front": {"type": 0, "data": "什么是光合作用?", "lang": "zh-CN"},
    "back": {"type": 1, "data": "绿色植物利用光能制造有机物。", "lang": null}
  },
  "options": {}
}

字段包装中的 type0 文本、1 HTML;lang 可为语言代码或 null。选择题的选项可使用 AH 作为字段名;返回结果会兼容旧客户端,使用 @option.A 这类名称。卡片响应字段包括 idsndeck_idcategory_snstyletitledataoptionsordercreated_atupdated_at_usn_synced

不传 templateSN 时,桌面版会按样式和字段名自动选择模板。categorySN 也可以用 categorySncategory_sn 或目录名称 category 传入。order 用于指定卡片顺序,正反卡应分别传入各自顺序。

同标题卡片的处理由 title_conflict 控制:

  • replace(默认):找到完全相同标题时更新已有卡片。
  • ignore:找到完全相同标题时直接返回已有卡片,不创建或修改。
  • keepboth:保留已有卡片并创建新卡片。

搜索接口的 limit 范围为 1 到 1000,默认 1000;query 会去除首尾空格。搜索和标题冲突检查返回的是主卡片,不包含反向卡片。

十、资源接口

方法和路径请求参数返回
POST /decks/{deckId}/resources/upload?filename=...查询参数 filename;正文为二进制文件资源对象
POST /decks/{deckId}/resources/delete?name=...查询参数 name文本 ok
POST /decks/42/resources/upload?filename=hello.mp3
Content-Type: application/octet-stream
X-API-SECRET: <访问秘钥>

<文件二进制内容>

资源上传不使用 JSON,也不要把文件内容 Base64 后再嵌入 JSON。资源名称应使用牌组内唯一、可复用的文件名;删除前请确认没有其他卡片引用该资源。返回字段以 Core 当前资源对象为准,常见字段包括 nametypesizemd5urlrefs、状态和同步时间。

十一、错误处理

失败响应统一为 JSON:

{
  "error": {
    "code": "FORBIDDEN",
    "message": "访问秘钥无效"
  }
}
HTTP 状态常见错误码含义
400INVALID_ARGUMENTINVALID_JSONTEMPLATE_NOT_FOUND请求参数、JSON 或创建卡片时的模板匹配无效
401AUTH_REQUIREDAUTH_INVALID桌面版未登录或登录状态失效
403FORBIDDEN*_PERMISSION_DENIED*_NOT_EDITABLE秘钥无效或当前数据不可操作
404NOT_FOUNDDECK_NOT_FOUNDTEMPLATE_NOT_FOUNDCARD_NOT_FOUND接口或查询的实体不存在(创建卡片未匹配模板属于 400)
413PAYLOAD_TOO_LARGE请求正文超过大小限制
503Core 返回的可重试错误码桌面版核心服务暂时不可用,请稍后重试
500INTERNAL_ERROR服务内部错误;响应不会泄露内部异常详情

十二、旧客户端兼容性

  • 接口路径和卡片字段保持旧客户端使用的命名方式;桌面版内部会转换为 Core 的 typed 方法。
  • 请求 JSON 中的 categorySNtemplateSNtitle_conflictorder 等旧字段仍可使用,同时兼容对应的 camelCase 和 snake_case 写法。
  • 响应会递归转换普通对象键名为 snake_case,但卡片 datafieldsoptionsstyle 内部的自定义键名及值保持原样。
  • 桌面版当前不提供 /auth/login/auth/logout 路由;登录请在桌面版界面完成。
  • 如需程序化发现字段和参数,请以正在运行的桌面版返回的 /openapi.json 为准。

十三、安全建议

  • 只在可信局域网中开启客户端 API,避免把端口暴露到公网。
  • 优先使用 X-API-SECRET 请求头,不要把秘钥写入 URL、截图、脚本仓库或共享日志。
  • 自动化批量修改前先备份或导出牌组;删除牌组、目录、卡片和资源前先在测试牌组验证。
  • 修改本地数据后,按需调用牌组同步或全部同步接口,并等待同步完成。
  • 不再使用时关闭客户端 API;怀疑秘钥泄露时立即重置秘钥。

十四、排查问题

问题处理方式
/_check 无法访问确认桌面版正在运行且客户端 API 已开启;检查局域网地址、防火墙和端口占用。
返回 403 FORBIDDEN检查 X-API-SECRETsecret 查询参数;重置秘钥后必须更新调用方配置。
返回 401 AUTH_REQUIRED在桌面版界面完成登录,并确认登录会话未失效。
返回 400 TEMPLATE_NOT_FOUND检查 styletemplateSN 和字段名;不指定模板时确保牌组存在可匹配模板。
数据没有出现在其他设备客户端 API 先修改本地数据;调用 POST /sync 或指定牌组同步后再检查云端。