Webhooks
Receive signed callbacks when async generations complete or fail.
Two ways to get notified
1) Pass callback_url on an async generation request for a one-off callback. 2) Register a webhook endpoint to receive every generation.completed and generation.failed event. Registered webhooks are signed.
/api/webhooksJWTRegister a webhook endpoint. The response includes a signing secret (whsec_...), shown only once.
Parameters
urlstringrequiredHTTPS endpoint to receive eventseventsstring[]generation.completed, generation.failed (default: both)Response
{"id":"...","url":"https://...","events":["generation.completed","generation.failed"],"is_active":true,"secret":"whsec_...","created_at":"..."}{
"event": "generation.completed",
"created_at": "2026-06-28T12:00:00Z",
"data": {
"generation_id": "...",
"status": "completed",
"type": "video",
"model": "...",
"output_url": "https://cdn.picxstudio.com/...",
"credits_used": 120
}
}Verify the signature
Each delivery includes X-PicX-Signature: t=<unix_ts>,v1=<hex>. Compute HMAC-SHA256 over "{t}.{raw_body}" with your whsec_ secret and compare to v1 using a constant-time check. Reject if it doesn't match or if t is older than ~5 minutes.
import hmac, hashlib, time
def verify(secret, raw_body, header):
parts = dict(p.split('=', 1) for p in header.split(','))
ts, sig = parts['t'], parts['v1']
if abs(time.time() - int(ts)) > 300:
return False
expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)import crypto from 'crypto';
function verify(secret, rawBody, header) {
const { t, v1 } = Object.fromEntries(header.split(',').map(p => p.split('=')));
if (Math.abs(Date.now()/1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac('sha256', secret)
.update(Buffer.concat([Buffer.from(`${t}.`), rawBody])).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}Retries & delivery history
Failed deliveries (non-2xx or timeout) are retried up to 3 times with backoff. View attempts via GET /api/webhooks/{id}/deliveries.