Webhooks
Register an endpoint in Developers. Every delivery is signed with HMAC-SHA256 over timestamp.body and retried five times with backoff.
Events
transcription.completedtranscription.failedwebhook.test(sent by the test button)
Envelope
POST https://your-app.com/hooks/transcriptanything
x-td-event: transcription.completed
x-td-delivery: evt_…
x-td-signature: t=1761600000,v1=5f2c…
{
"id": "evt_…",
"type": "transcription.completed",
"created_at": "2026-10-27T09:00:00.000Z",
"data": {
"transcription_id": "trj_…",
"status": "succeeded",
"duration_seconds": 842,
"charged_credits": 41,
"result": {
"json": "/api/v1/transcriptions/trj_…/result?format=json",
"srt": "/api/v1/transcriptions/trj_…/result?format=srt",
"txt": "/api/v1/transcriptions/trj_…/result?format=txt",
"vtt": "/api/v1/transcriptions/trj_…/result?format=vtt"
}
}
}Verify the signature
// Node/Workers: the secret is returned once when the endpoint is created
const [timestampPart, signaturePart] = header.split(",");
const timestamp = Number(timestampPart.split("=")[1]);
const signature = signaturePart.split("=")[1];
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return reject("stale");
const key = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(secret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"],
);
const mac = await crypto.subtle.sign(
"HMAC",
key,
new TextEncoder().encode(timestamp + "." + rawBody),
);
const expected = [...new Uint8Array(mac)].map((b) => b.toString(16).padStart(2, "0")).join("");
if (expected !== signature) return reject("bad signature");Return 2xx within 5 seconds. Twenty consecutive failures disable the endpoint and you get an email. Re-enable it after fixing the receiver in Developers → Webhooks.