后台处理和回调
解析大量简历或分析一小时的面试录音不应保持连接打开。异步端点接受链接或上传,立即返回 task_id,并在我们的服务器上运行工作。通过轮询收集结果,或将其发送到您的服务器。
异步端点
| 端点 | 输入 | 结果 |
|---|---|---|
POST /parse/async | 最多25个CV链接(file_urls),或上传 files | 每个CV一个解析结果,按顺序,形状与 POST /parse/ |
POST /evaluate/async | 最多25个CV链接(resume_urls),或上传 resume_pdfs,加上 job_details ,或 job_id | 每个CV一个评估结果,按顺序,形状与 POST /evaluate/ |
POST /summary/async | 一个录音链接(media_url),或一个上传的 media 文件;可选 interview_id 和 language | transcript_text, transcript_entries 和 summary |
POST /transcribe/async | 一个录音链接(media_url),或一个上传的 media 文件 | transcript_text 和 transcript_entries |
POST /translate/async | text, texts 或文档链接(file_urls),或上传 files;source_language 和 target_language | 形状与 POST /translate/ |
每个异步请求也可能包含一个 callback_url.
| 轮询端点 | 返回值 |
|---|---|
GET /{op}/tasks/{task_id} | 任务的状态和完成后的结果。 {op} 是 parse、evaluate、summary、transcribe 或 translate. |
发送任务
发送 application/json 包含链接列表,或 multipart/form-data 包含上传文件。在multipart中,链接字段可以重复或每行发送一个链接。
curl -X POST https://api.curriculo.me/public/parse/async \
-H 'Authorization: Bearer key_abc123_yoursecret' \
-H 'Content-Type: application/json' \
-d '{"file_urls": ["https://example.com/cvs/candidate_a.pdf", "https://example.com/cvs/candidate_b.pdf"], "callback_url": "https://example.com/curriculo/callback"}'curl -X POST https://api.curriculo.me/public/summary/async \
-H 'Authorization: Bearer key_abc123_yoursecret' \
-H 'Content-Type: application/json' \
-d '{"media_url": "https://example.com/interviews/interview.mp4", "interview_id": "int_0042", "language": "ko"}'curl -X POST https://api.curriculo.me/public/translate/async \
-H 'Authorization: Bearer key_abc123_yoursecret' \
-H 'Content-Type: application/json' \
-d '{"texts": ["Senior backend engineer", "Remote within Europe"], "source_language": "en", "target_language": "fr"}'对于 JSON 请求到
/translate/async,需要source_language。对于/evaluate/async,将作业发送为job_details或job_id.
API 立即回答,带有 202:
{ "task_id": "…", "status": "queued", "callback_secret": "whsec_…" }callback_secret 仅当发送 callback_url时返回。它显示一次,像 API 键一样,因此请存储它。
获取结果
轮询
curl https://api.curriculo.me/public/parse/tasks/<task_id> \
-H 'Authorization: Bearer key_abc123_yoursecret'任务可以使用创建它的相同密钥读取,无论是否已发送回调。响应从不包含回调 URL 或密钥。
| 字段 | 含义 |
|---|---|
task_id | 任务的ID |
op | 任务运行的操作 |
status | queued, processing, succeeded 或 failed. |
status_code | 操作完成后产生的HTTP状态 |
result | 操作的响应体,一旦 status 是 succeeded;null 之前 |
error | 任务失败时的错误消息 |
delivery | 回调传递状态: not_requested,pending,delivered 或 dead,以及尝试次数 |
created_at, completed_at | 时间戳 |
回调
如果您发送了 callback_url,则完成的任务将以 application/json 的形式POST到那里,包含以下头部
| 头部 | 值 |
|---|---|
X-Curriculo-Signature | sha256=<hex>: 请求体的精确原始内容的十六进制小写形式 HMAC-SHA256,以您的 callback_secret |
X-Curriculo-Task-Id | 任务的ID |
Content-Type | application/json |
请求体是 {task_id, op, status, status_code, result, error, completed_at}.
没有时间戳头,因此在 task_id上去除重复的投递:如果您的服务器反应慢或返回错误,相同的任务可能会多次到达.
验证签名
计算原始请求体的 HMAC-SHA256,使用您的 callback_secret 完全按照返回的结果(包括 whsec_ 前缀)作为密钥。比较 sha256= 加上十六进制小写摘要与 X-Curriculo-Signature 在恒定时间内。使用原始字节,如接收到的那样,在任何 JSON 解析之前,并拒绝任何不匹配的内容.
Python:
import hashlib
import hmac
def is_valid(raw_body: bytes, signature_header: str, callback_secret: str) -> bool:
# callback_secret is used as-is, including the "whsec_" prefix
expected = "sha256=" + hmac.new(
callback_secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header or "")JavaScript (Node.js):
import crypto from "node:crypto";
// rawBody must be the unparsed request body (a Buffer)
export function isValid(rawBody, signatureHeader, callbackSecret) {
const expected =
"sha256=" +
crypto.createHmac("sha256", callbackSecret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}然后在 X-Curriculo-Task-Id 标头(或 task_id 中)进行去重,并回答 2xx.
交付和重试
- 任何非
2xx答案都被视为交付失败,重定向也不被跟踪。 - 交付重试采用递增延迟(1、5、15 和 60 分钟,然后 4 小时),总共约 5 小时 21 分钟,直到交付被标记
dead. - 结果在
GET /{op}/tasks/{task_id}任意情况下都保持可读,因此不会因错过交付而丢失。
URL 要求
回调 URL 必须是
https、公开可访问的,并且不包含凭据。私有网络上的地址将被拒绝。
- 您发送的链接(
file_urls、resume_urls、media_url)必须是公开的https链接。公开链接或预签名存储 URL(例如 S3)均可。 - 重定向的链接将被拒绝。
- 通过链接的录音最长可达 1 GB 和 2 小时。上传的文件每个最多限制为 12 MB。
计费
- 任务按其最终结果计费一次,即其操作的一个请求:异步解析25个链接的费用为$0.01。
- 失败的任务(死链、不可读文件)永远不会被计费。
- 记录任务(
/summary/async、/transcribe/async)在任务被接受时预留2小时最大费用。如果没有足够的信用用于预留,请求返回400。如果任务失败,预留将被释放。
请参阅 定价和计费.
任务保留的数据
与同步操作不同,后台任务保留其结果,因此您可以轮询它,上传的文件存储在您的帐户下。请参阅 数据处理.
Updated