Webhooks
Set a webhook URL when creating a job to receive an HTTPS POST each time a target finishes. Use webhooks for production integrations; polling remains the fallback.
Configure a receiver
Pass webhookUrl to Create a separation job. Use HTTPS in production. Local development may use http://127.0.0.1 or http://localhost; use an HTTPS tunnel when testing a publicly reachable receiver.
A single job can include multiple targets. Gaudio sends one webhook delivery per target when that target reaches a terminal state:completed or failed.
Acknowledge quickly
Return any 2xx response within 10 seconds to acknowledge delivery. Do signature verification and enqueue follow-up work, but avoid long processing in the request handler.
Any non-2xx response, timeout, connection failure, or TLS failure is treated as a failed delivery.
Handle retries idempotently
Failed deliveries are retried up to 5 times with exponential backoff of about 1 minute, 5 minutes, 30 minutes, 2 hours, and 6 hours. Retries can arrive more than once or out of order.
Use jobId plus target.model as an idempotency key when updating your own state.
Verify the signature
Each delivery includes an X-Gaudio-Signature header. The value is prefixed with sha256=. Compute the HMAC-SHA256 hex digest of the raw request body using your webhook signing secret, add the same prefix, then compare it before trusting the payload.
import hmac
import hashlib
import os
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
secret = os.environ["GAUDIO_WEBHOOK_SIGNING_SECRET"]
@app.post("/gaudio/webhook")
async def receive_webhook(request: Request):
body = await request.body()
received = request.headers.get("x-gaudio-signature", "")
expected = hmac.new(
secret.encode("utf-8"),
body,
hashlib.sha256,
).hexdigest()
expected = "sha256=" + expected
if not hmac.compare_digest(expected, received):
raise HTTPException(status_code=401, detail="Invalid signature")
payload = await request.json()
# Enqueue work here; return 2xx quickly so delivery is acknowledged.
return {"ok": True}Target completed
{your webhookUrl}Headers
X-Gaudio-SignatureRequiredHMAC-SHA256 of the raw request body, hex-encoded, using your webhook signing secret. Verify this before processing the payload.
Payload
jobIdstringRequiredThe job this target belongs to.
targetTargetResultRequiredmodelstringRequiredThe model alias this result corresponds to.
tierenumOptionalThe processing tier this target was processed with. Present for DME targets only.
Allowed values: premiumstandardlive
statusenumRequiredStatus of this individual target.
Allowed values: queuedprocessingcompletedfailed
progressintegerOptionalCompletion percentage for this target. A completed target reports 100.
outputmap<string, map<string, string (uri)>>OptionalDownload links, keyed by stem name and then by format (for example output.dialogue.wav). Present once status is completed.
errorTargetErrorOptionalFailure details. Present only when status is failed.
codeenumRequiredA stable, machine-readable code. New codes may be added over time — treat an unrecognised one as a generic failure and fall back to retryable.
Allowed values: PROCESSING_FAILEDPROCESSING_TIMEOUTQUEUE_TIMEOUTSOURCE_EXPIREDJOB_CANCELLED
messagestringRequiredA human-readable explanation. Fixed per code — safe to show to an end user, but do not parse it or branch on its wording.
retryablebooleanRequiredWhether resubmitting the same source can succeed. true means the failure was transient (an interrupted run, a timeout, or no capacity in time) — retry with backoff. false means retrying changes nothing.
{
"jobId": "job_91b2e0",
"target": {
"model": "dme_dialogue_v1",
"tier": "premium",
"status": "completed",
"output": {
"dialogue": {
"wav": "https://cdn.example.com/job_91b2e0/dialogue.wav"
}
}
}
}Your response
Return any 2xx status to acknowledge receipt. Response body is ignored.
