Webhooks
Get a POST to your URL when an async job completes or fails. Durable delivery: 6 attempts with exponential backoff (30 s, 60 s, 120 s, 240 s, 480 s, 960 s), survives gateway restarts.
Register
POST /v1/webhooks HTTP/1.1
Authorization: Bearer <jwt>
Content-Type: application/json
{ "url": "https://yourapp.example.com/hooks/pixozip" }Response (the secret is shown once):
{ "id": "...", "url": "...", "secret": "whsec_...", "createdAt": "..." }Payload
{
"event": "job.completed",
"jobId": "f5012a57-9bd7-47b9-9eaf-6f9c00356872",
"status": "completed",
"outputBytes": 8465,
"ratio": 0.74,
"finishedAt": "2026-05-24T09:45:11.402Z"
}event is one of job.completed, job.failed. The header
X-Img-Signature: sha256=<hex hmac> is computed with your secret on the
raw body.
Verify (Node)
import crypto from "node:crypto";
function verify(rawBody: Buffer, header: string, secret: string): boolean {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(header);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Verify (PHP)
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_IMG_SIGNATURE'] ?? '')) {
http_response_code(401); exit;
}Idempotency on your side
We may deliver the same event more than once on the rare retry — dedupe on
(jobId, event, finishedAt).
Manage
GET /v1/webhooks— list registered URLs.DELETE /v1/webhooks/:id— remove.