XRToken API Docs

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

HeaderDescription
Content-Typeapplication/json
X-XRToken-TimestampSend timestamp (Unix seconds)
X-XRToken-Signaturesha256=<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 2xx within 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 dropped and will not be retried; task results remain available via GET /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.

On this page