Skip to content

后台处理和回调

On this page

解析大量简历或分析一小时的面试录音不应保持连接打开。异步端点接受链接或上传,立即返回 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 和 languagetranscript_text, transcript_entries 和 summary
POST /transcribe/async一个录音链接(media_url),或一个上传的 media 文件transcript_text 和 transcript_entries
POST /translate/asynctext, 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任务运行的操作
statusqueued, 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-Signaturesha256=<hex>: 请求体的精确原始内容的十六进制小写形式 HMAC-SHA256,以您的 callback_secret
X-Curriculo-Task-Id任务的ID
Content-Typeapplication/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