开放 API 与 Webhook 对接文档
把轻聘 ATS 的职位与候选人接进你自己的系统(HR 系统 / 招聘中台 / 自动化脚本)。
三步跑通
- 工作台 → 开放 API → 创建密钥(明文只显示一次,立刻保存)。
- 把下面的
curl示例复制走,先调GET /api/v1/jobs确认鉴权通了。 - 要实时通知就到 Webhook 填你的接收地址,用验签密钥校验推送(下方有现成验签代码)。
开放 API 与 Webhook 是专业版功能;密钥只存哈希,丢了只能吊销重建,客服也无法帮你找回明文。
通用约定
- Base URL:
https://qingats.itianshu.cn- 鉴权:
- 请求头
Authorization: Bearer ats_xxx。走密钥不走 Cookie,与网页登录态无关;吊销后立即失效。 - 编码:
- 请求与响应均为 UTF-8 JSON。
| 状态码 | 含义 | 处理建议 |
|---|---|---|
| 401 | invalid_api_key:没带 / 填错 / 已吊销的密钥 | 检查 Bearer 头;到工作台确认密钥未吊销 |
| 400 | 参数错误(message 是中文原因) | 按提示修正参数 |
| 503 | 数据库尚未初始化 | 服务端迁移未完成,稍后重试 |
GET/api/v1/jobs
列出密钥属主名下的全部职位(含每个职位的候选人数),按创建时间倒序。
查询参数
| 参数 | 必填 | 说明 |
|---|---|---|
| limit | 否 | 返回条数,1–200,默认 50,超出范围自动钳制 |
调用示例
curl 'https://qingats.itianshu.cn/api/v1/jobs?limit=20' \ -H 'Authorization: Bearer ats_你的密钥'
响应示例
{
"jobs": [
{
"id": 3,
"title": "前厅经理",
"dept": "门店运营",
"status": "open",
"created_at": "2026-10-15T08:30:00.000Z",
"candidate_count": 12
}
]
}字段说明:status 为 open(在招)/ closed(已关闭);created_at 是 ISO 8601 字符串;candidate_count 是该职位下的候选人总数。
GET/api/v1/candidates
列出候选人,可按职位 / 阶段过滤,按 id 倒序。
查询参数
| 参数 | 必填 | 说明 |
|---|---|---|
| job_id | 否 | 按职位过滤(数字,必须是名下职位) |
| stage | 否 | 按阶段过滤,枚举:待筛选 / 面试中 / offer / 淘汰 |
| limit | 否 | 返回条数,1–200,默认 50 |
调用示例(含中文参数,用 --data-urlencode 免转码)
curl -G 'https://qingats.itianshu.cn/api/v1/candidates' \ --data-urlencode 'job_id=3' \ --data-urlencode 'stage=面试中' \ --data-urlencode 'limit=20' \ -H 'Authorization: Bearer ats_你的密钥'
响应示例
{
"candidates": [
{
"id": 88,
"name": "张三",
"email": "zhangsan@example.com",
"job_id": 3,
"stage": "面试中",
"note": "内推,5 年连锁餐饮经验",
"created_at": 1760582400000,
"job_title": "前厅经理"
}
]
}字段说明:created_at 是毫秒时间戳(2026-10-16 之前登记的老数据为 0);job_title 是关联职位的名称。
POST/api/v1/candidates
创建一个候选人(Body 为 JSON)。创建成功会触发 candidate.created Webhook 推送。
Body 参数
| 参数 | 必填 | 说明 |
|---|---|---|
| name | 是 | 候选人姓名,最长 60 字 |
| job_id | 是 | 职位 id(数字,必须是名下职位,否则 400) |
| 否 | 邮箱,最长 120 字 | |
| stage | 否 | 初始阶段,默认「待筛选」;非法值也会归一化为「待筛选」 |
| note | 否 | 备注,最长 500 字 |
调用示例
curl -X POST 'https://qingats.itianshu.cn/api/v1/candidates' \
-H 'Authorization: Bearer ats_你的密钥' \
-H 'Content-Type: application/json' \
-d '{"name":"李四","email":"lisi@example.com","job_id":3,"stage":"待筛选","note":"来自招聘网站"}'响应示例
{
"ok": true,
"candidate": {
"id": 89,
"name": "李四",
"email": "lisi@example.com",
"job_id": 3,
"stage": "待筛选",
"note": "来自招聘网站",
"created_at": 1760582400000
}
}Webhook 对接(接收事件推送)
在工作台 → Webhook 填你的接收地址并勾选订阅事件。有动作时,轻聘 ATS 会向该地址发 POST 请求。
事件列表
| 事件 | 触发时机 | data 内容 |
|---|---|---|
| candidate.created | 新增候选人(网页添加或开放 API 创建都会触发) | candidate:完整候选人记录 |
| candidate.stage_changed | 候选人阶段变更 | id / stage(新阶段)/ from(原阶段)/ candidate:完整记录 |
推送格式
POST /ats/webhook HTTP/1.1 content-type: application/json user-agent: QingATS-Webhook/1.0 x-ats-event: candidate.stage_changed x-ats-signature: sha256=9f2c8e...(HMAC-SHA256,hex 小写)
{
"event": "candidate.stage_changed",
"created_at": 1760582400000,
"data": {
"id": 89,
"stage": "面试中",
"from": "待筛选",
"candidate": { ... } // 完整候选人记录,字段同 candidate.created
}
}顶层 created_at 与候选人记录里的 created_at 均为毫秒时间戳。
验签(Node.js / Express 示例)
签名 = HMAC-SHA256(验签密钥, 原始请求体),hex 小写,放在 X-ATS-Signature 头(带 sha256= 前缀)。⚠️ 必须拿原始请求体计算——先解析 JSON 再重新序列化会得到不同字节,验签必然失败。
// Express 示例:先拿原始请求体再验签(不能先 JSON.parse 再重新序列化)
app.post('/ats/webhook', express.raw({ type: '*/*' }), (req, res) => {
const crypto = require('crypto')
const secret = 'whsec_xxxx' // 创建 Webhook 时保存的验签密钥
const sig = String(req.headers['x-ats-signature'] || '')
const expect = 'sha256=' +
crypto.createHmac('sha256', secret).update(req.body).digest('hex')
if (sig !== expect) return res.status(401).send('bad signature')
const payload = JSON.parse(req.body.toString('utf8'))
if (payload.event === 'candidate.created') {
console.log('新候选人:', payload.data.candidate.name)
} else if (payload.event === 'candidate.stage_changed') {
console.log(`候选人 ${payload.data.id}:${payload.data.from} → ${payload.data.stage}`)
}
res.sendStatus(200) // 返回 2xx 即视为投递成功
})投递行为(对接前必读)
- 超时 5 秒;你的接口返回 2xx 才算投递成功。
- 失败不会自动重试;每次投递(含失败原因)都在 工作台 → Webhook → 最近投递记录 里可查。
- 只推送你勾选订阅的事件;投递失败绝不影响业务动作本身(候选人该建成功还是成功)。
- 建议接收端做幂等:同一事件理论上可能因网络重发收到不止一次。
对接调试技巧
- 401 先查三件事:Bearer 头拼写、key 是否以
ats_开头、工作台里是否已吊销。 - 收不到推送:先看工作台的投递记录——有记录且 status=0 是你服务端的问题(超时 / 非 2xx / 签名错);没记录说明事件没触发或没勾选订阅。
- 验签失败:99% 是用了重新序列化后的 body。务必用原始字节计算(见上方 express.raw 示例)。
- 本地联调可用 webhook.site 之类的临时接收地址,先看真实推送长什么样。
- 测试完记得吊销测试密钥;secret 只在创建时显示一次。
轻聘 ATS · 招聘管理 · qingats.itianshu.cn