Webhooks

Get the result pushed to you, signed with your secret.

How it works

Pass a callback_urlwhen you start any job, and we’ll POST the result to it the moment the job succeeds or fails. The body carries exactly what GET /jobs/{id} returns, under data, so the code you wrote for polling handles it as-is.

What we send
{  "data": {    "charged_usd": 0.06,    "error": null,    "id": "…",    "output_url": "https://…",    "status": "succeeded"  },  "delivery_id": "…",  "event": "job.succeeded",  "sent_at": "2026-09-26T09:31:07Z"}

event is job.succeeded or job.failed. Failures are delivered too. Live sessions don’t send webhooks.

Headers on every delivery

FieldTypeRequiredDescription
KreatorsFactory-SignaturestringNot=<unix time>,v1=<hex>. Check this before trusting the body.
KreatorsFactory-EventstringNoSame as event in the body, so you can route without parsing.
KreatorsFactory-DeliverystringNoSame as delivery_id. Stays the same across retries of one delivery.

Check every delivery

An unchecked webhook URL is an open door

Anyone who learns your URL can post “your job succeeded, here’s the file”. Check the signature, and reject the delivery if it doesn’t match.

The hex is an HMAC-SHA256 of <t>.<raw body>, keyed with your signing secret. Hash the raw bytes you received: parsing and re-serialising the JSON changes the spacing and the digest won’t match.

# Webhooks come TO you, so there is nothing to call.# Pass callback_url when you start a job:curl -X POST https://api.kreatorsfactory.com/api/v1/face-swap-image \  -H "Authorization: Bearer $KREATORSFACTORY_API_KEY" \  -H "Content-Type: application/json" \  -d '{"image_key":"api/images/…","face_key":"api/images/…","callback_url":"https://yourapp.com/webhooks/kreatorsfactory"}'

Your signing secret is on the Webhooks page in the console. One secret covers your whole account and keeps working when you rotate an API key; rotate it separately if it is ever exposed.

Delivery and retries

FieldTypeRequiredDescription
Success2xxNoAny 2xx counts as delivered. Reply first and do the work after.
Timeout10 secondsNoWe wait ten seconds for your reply before counting it as a failure.
Retries6 attemptsNoAnything else is retried, up to six attempts in total, then given up.
Duplicatesdelivery_idNoThe same on every retry. Key on it to be sure you act once.

Webhooks don't replace the job endpoint

If your server was down for every attempt, the job is still there: GET /jobs/{id} is the source of truth.