接入流程

开放平台提供简历文件/内容解析、简历编辑、AI 和 PDF 生成能力,不负责永久保存第三方简历。每次草稿自动保存成功后,iframe 通过 saved 事件把完整简历 JSON 交给父页面,接入方自行保存。

API 根地址:https://www.qmjianli.com/api_open
编辑器来源:https://www.qmjianli.com
开发者中心:/open/developer/

两种接入方式

  1. 嵌入编辑器:创建会话后把 editorUrl 放进 iframe,用户在官方编辑器里改简历、用 AI、导出 PDF。
  2. 直接调用 API:解析简历得到 resumeData,再按需打开编辑器生成 PDF

完整流程

用户点击“编辑简历” → 接入方后端拉取模板列表,用户选择模板 → 接入方后端用 appSecret 创建临时会话 → 创建会话时把选中模板写入 resumeData.setData.tplId → 后端将 editorUrl 返回给自己的前端 → 前端立即将 editorUrl 放进 iframe → 用户编辑,草稿临时保存在平台(最长 24 小时) → 编辑器自动保存草稿 → iframe 向已校验的父页面发送 saved 事件和完整 resumeData → 若 JSON 里有平台临时照片地址,接入方转存并替换成自己的 URL → 父页面自行保存、转换或丢弃 JSON

第一步:创建应用

  1. 登录开发者中心,进入“应用管理”。
  2. 创建应用,填写应用名称和允许嵌入域名
  3. 允许域名必须是完整 Origin,例如 https://hr.example.com。不要填写路径,例如 /resume/edit
  4. 保存创建后只显示一次的 appSecret。它只能放在接入方后端。
应用配置的允许域名、创建会话传入的 parentOrigin、实际父页面 Origin 三者必须完全一致,包括协议和端口。

第二步:获取简历模板列表

生成新简历前,接入方后端可以先拉取可用模板,让用户选择。详见 获取简历模板。该接口需要使用 appSecret,不要在浏览器中直接调用:

GET https://www.qmjianli.com/api_open/v1/templates
Authorization: Bearer {appSecret}

成功返回:

{
  "code": 1,
  "data": [
    {
      "templateId": 1013,
      "tags": "通用,简洁",
      "skin": "#1575bf",
      "coverUrl": "https://www.qmjianli.com/img/resume/template/online/1013.png"
    }
  ]
}

前端展示 coverUrl,并把用户选中的 templateId 提交给接入方后端。模板列表可以短期缓存,但创建会话仍应在用户开始编辑时进行。

第三步:后端创建会话

用户点击编辑时,由接入方后端调用:

POST https://www.qmjianli.com/api_open/v1/editor-sessions
Authorization: Bearer {appSecret}
Content-Type: application/json

{
  "externalResumeId": "R10001",
  "parentOrigin": "https://hr.example.com",
  "resumeData": {
    "setData": { "tplId": 1013 }
  }
}

parentOriginexternalResumeId 是必填项。externalResumeId 是接入方的简历 ID,最长 128 个字符且必须在当前应用内唯一。新简历把选中模板写入 resumeData.setData.tplId;不传则使用默认模板 1013。已有简历首次创建会话时,把上次 saved 事件拿到的 JSON 放进 resumeData(照片须已换成接入方自己的 URL)。

成功返回:

{
  "code": 1,
  "data": {
    "sessionId": "S...",
    "editorUrl": "https://www.qmjianli.com/open/edit?code=C...",
    "expiresAt": "2026-08-15T02:00:00.000Z"
  }
}
editorUrl 内的一次性 code 只有 60 秒有效且只能使用一次。拿到后应立即打开 iframe。iframe 自身刷新会自动恢复;父页面刷新后,使用相同 externalResumeId 再次调用本接口即可恢复 24 小时内的原会话并获得新的 editorUrl。

第四步:前端嵌入 iframe

<iframe
  id="qm-resume-editor"
  src="后端返回的 editorUrl"
  style="width: 100%; height: 100vh; border: 0;"
></iframe>

第五步:监听自动保存事件

父页面必须同时校验 event.originevent.source,不能只判断事件名:

var iframe = document.getElementById("qm-resume-editor");

window.addEventListener("message", function (event) {
  if (event.origin !== "https://www.qmjianli.com") return;
  if (event.source !== iframe.contentWindow) return;

  var message = event.data;
  if (!message || message.source !== "QM_RESUME_EDITOR") return;

  if (message.event === "saved") {
    // 完整简历 JSON。basicInfo.photo 若是平台临时地址,须转存后替换再保存。
    saveToYourOwnServer(message.externalResumeId, message.resumeData);
  }
});

编辑器发送消息时也不会使用通配符 *,只会向创建会话时已经通过白名单校验的 parentOrigin 发送。

第六步(可选):生成 PDF

用户可在编辑器中点击“导出 PDF”,也可由接入方后端直接提交 resumeData 调用生成 PDF。两种方式都同步返回临时下载地址。

{
  "source": "QM_RESUME_EDITOR",
  "event": "exported",
  "externalResumeId": "R10001",
  "downloadUrl": "https://www.qmjianli.com/api_open/v1/files/...",
  "expiresAt": "..."
}

该地址只服务本次下载,过期后不保证再次打开。需要时让用户重新导出即可。

接入方最小后端示例

app.post("/api/resume/editor-url", async function (req, res) {
  var response = await fetch(
    "https://www.qmjianli.com/api_open/v1/editor-sessions",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": "Bearer " + process.env.QM_APP_SECRET
      },
      body: JSON.stringify({
        externalResumeId: String(req.body.resumeId || ""),
        parentOrigin: "https://hr.example.com",
        resumeData: req.body.resumeData || { setData: { tplId: 1013 } }
      })
    }
  );
  var result = await response.json();
  if (result.code !== 1) {
    return res.status(400).json({ message: result.data });
  }
  res.json({ editorUrl: result.data.editorUrl });
});

平台不负责什么

  • 不负责接入方简历的永久存储。
  • 不负责简历照片的永久存储。编辑器上传后给出的是临时地址,接入方须转存并替换。
  • 不判断父页面是否已经把 saved 事件写入数据库。
  • 不提供 PDF 历史文件管理。
  • 不要求最终用户登录全民简历个人账号。
全民简历开放平台 · 与个人简历账号完全独立