Webhooks
Async event delivery, signature verification, retry policy
API Configuration
After saving, the Try It panel below sends real requests with this key.
Base: api.xrtoken.ai
Async tasks such as video generation can register a callback via callback_url. When a task reaches a terminal state (succeeded / failed), XRToken will POST to your URL — no polling needed.
Enable callbacks
Add callback_url to your POST /v1/videos/generations request body:
{
"model": "doubao-seedance-2-0-260128",
"content": [{ "type": "text", "text": "..." }],
"callback_url": "https://your.app/webhooks/xrtoken"
}Payload format
{
"task_id": "5e1f2c8a-...",
"status": "succeeded",
"model": "doubao-seedance-2-0-260128",
"video_url": "https://tos.../video.mp4",
"created_at": "2026-04-15T10:00:00Z",
"finished_at": "2026-04-15T10:01:32Z"
}On failure:
{
"task_id": "5e1f2c8a-...",
"status": "failed",
"model": "doubao-seedance-2-0-260128",
"error": { "code": "task_failed", "message": "..." },
"created_at": "...",
"finished_at": "..."
}Request headers
| Header | Description |
|---|---|
Content-Type | application/json |
X-XRToken-Timestamp | Send timestamp (Unix seconds) |
X-XRToken-Signature | sha256=<hex>, HMAC-SHA256 signature |
Verify the signature
Signature computation:
HMAC_SHA256(secret, timestamp + "." + raw_body)secret is your account's Webhook Secret (Dashboard > Settings > Webhooks; starts with whsec_).
Node.js example:
import crypto from 'node:crypto'
function verify(req, secret) {
const ts = req.headers['x-xrtoken-timestamp']
const sig = req.headers['x-xrtoken-signature'] // 'sha256=...'
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(ts + '.' + req.rawBody) // Note: use the raw unparsed body
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
}Python example:
import hmac, hashlib
def verify(headers, raw_body, secret):
ts = headers['x-xrtoken-timestamp']
sig = headers['x-xrtoken-signature'].split('=', 1)[1]
expected = hmac.new(
secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(sig, expected)After verifying the signature, check that timestamp is within 5 minutes of current time to prevent replay attacks.
Response and retries
- Your endpoint must return
2xxwithin 10 seconds; otherwise the attempt is considered failed - Failed/timed-out deliveries are retried up to 3 times at intervals of
5s / 30s / 5min - After 4 total failures the delivery is marked
droppedand will not be retried; task results remain available viaGET /v1/videos/generations/{taskId}
Idempotency
The same task_id callback may arrive more than once during retries. Your endpoint should use task_id as an idempotency key.