接口
回调通知
任务结束后,我们把结果 POST 到你的地址,附上签名,没收到会重试。
提交任务时传 callback_url(必须是 https 公网地址)。任务完成或失败后,我们向这个地址 POST 任务对象,内容和 GET /v1/tasks/TASK_ID 返回的一样。
请求带这几个 Header:
Content-Type: application/json X-Relay-Task-Id: task_9f2c... X-Relay-Attempt: 1 X-Relay-Signature: 9b1d0c...
重试
你的服务返回 2xx 就算收到。返回其他状态码、10 秒内没有响应、或者返回跳转(我们不跟随跳转),都算失败,稍后会再发:总共最多 6 次,分别在 10 秒、1 分钟、5 分钟、30 分钟、2 小时后重发。X-Relay-Attempt 是第几次发送。
同一个任务可能收到不止一次,比如你的响应在回程中丢了。请按任务 ID 去重,每个任务只处理一次。
送达状态
任务的 callback 字段记录了送达情况:
"callback": {
"url": "https://example.com/hooks/relay",
"status": "delivered",
"attempts": 1,
"last_attempt_at": "2026-10-21T08:00:13.000Z",
"last_error": null
}status:waiting(任务还在运行)、pending(正在发送或等待重试)、delivered(已送达)、failed(全部尝试都失败了)。last_error:最近一次失败的原因,比如HTTP 500或no response within 10s。
控制台的任务详情里也能看到。
重新发送
想再收一次已结束任务的回调(比如修好了接收地址),在控制台的任务详情里点 重新发送,或者调用:
curl -X POST https://janvia.io/v1/tasks/TASK_ID/callback \ -H "Authorization: Bearer $API_KEY"
会重新开始一轮发送,返回 202 和任务对象。任务还在运行、或者没有 callback_url 时返回 400。
回调只是通知。没收到时,用 GET /v1/tasks/TASK_ID 查询结果即可。在线试用提交的任务没有回调。
验证签名
X-Relay-Signature 是对原始请求体做 HMAC-SHA256 的十六进制结果。密钥是提交这个任务的 API 密钥的 SHA-256 十六进制字符串。请用收到的原始字节计算,不要把 JSON 解析后再重新序列化。如果这个密钥已经删除,请求不带签名。
Node.js:
import { createHash, createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody, signature, apiKey) {
const secret = createHash('sha256').update(apiKey).digest('hex');
const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
return (
signature.length === expected.length &&
timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
);
}Python:
import hashlib, hmac
def verify(raw_body: bytes, signature: str, api_key: str) -> bool:
secret = hashlib.sha256(api_key.encode()).hexdigest().encode()
expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)