Webhooks
Skip polling. When you create a transcription, pass a webhook_url and we push the finished payload to your server the moment it's ready.
Register a webhook
There's no separate subscription resource — a webhook is bound to a single transcription via the webhook_url field at creation time. Use any HTTPS URL you control.
curl -X POST https://api.quillhub.ai/v1/transcriptions \
-H "Authorization: Bearer $QAI_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://youtu.be/dQw4w9WgXcQ",
"webhook_url": "https://your-app.example.com/hooks/quillai"
}'Events
Exactly one event fires per transcription, once it reaches a terminal state:
transcription.completed— transcription finished successfully; result is populated.transcription.failed— transcription failed; error contains the reason and no points are charged.
Payload
The body is the full Transcription object — the same shape returned by GET /v1/transcriptions/{id}. See the API reference for the complete schema.
{
"id": "trs_01HZX9K7Q2M4YV8BTA6JRN3PDE",
"status": "completed",
"source": { "type": "youtube", "url": "https://youtu.be/dQw4w9WgXcQ" },
"duration_seconds": 842,
"points_spent": 14,
"result": {
"text": "Welcome back to the channel. Today we're talking about...",
"segments": [ /* ... */ ],
"structured": { /* ... */ },
"subtitles": {
"vtt": "https://storage.quillhub.ai/subtitles/...vtt",
"srt": "https://storage.quillhub.ai/subtitles/...srt"
}
},
"webhook_url": "https://your-app.example.com/hooks/quillai",
"error": null,
"created_at": "2026-04-23T10:12:03Z",
"completed_at": "2026-04-23T10:14:27Z"
}Headers
X-QuillAI-Event— the event type, either transcription.completed or transcription.failed.X-QuillAI-Delivery— a unique UUID for this delivery attempt. Use it to dedupe if a retry arrives after you already processed the first call.
We also send Content-Type: application/json and User-Agent: QuillAI-Webhooks/1.0.
Retries
A delivery succeeds when your endpoint returns a 2xx status within 10 seconds. Anything else — non-2xx, timeout, connection error — triggers retries on a fixed schedule: 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours. After 5 retries (6 attempts total) the delivery is abandoned and no further attempts are made for that event.
Testing locally
There's no sandbox endpoint for webhooks yet. To test against local code, expose your dev server with a tunnel like ngrok or smee.io and use the resulting public URL as webhook_url on a qai_test_ key.