Webhook Events & Real-Time Job Notifications

Webhooks let your app react the moment a transcription job completes or fails — no polling required. Register an endpoint and Wisprs will POST a signed payload to your URL.

Why webhooks instead of polling?

Polling GET /api/v1/jobs/{id} works fine for short scripts, but for production systems webhooks are more reliable and efficient. Your server only wakes up when there's something to handle, and you get completion events even if your polling loop restarts or misses a cycle.

Register an endpoint

import { WisprsClient } from '@wisprs/sdk'; const client = new WisprsClient({ apiKey: process.env.WISPRS_API_KEY! }); const endpoint = await client.webhooks.createEndpoint({ url: 'https://your-app.com/webhooks/wisprs', }); console.log(endpoint.signingSecret); // shown once — save this
json
{ "success": true, "data": { "endpoint": { "id": 7, "url": "https://your-app.com/webhooks/wisprs", "signingSecret": "whsec_your_secret", "isActive": true } } }

Save the signingSecret — it's shown once and used to verify signatures.

Webhook endpoint registration form
Dashboard → Settings → API → Webhook Endpoints — register and test your callback URL

Verify the signature

import { createHmac, timingSafeEqual } from 'node:crypto'; export async function POST(req: Request) { const body = await req.text(); const sig = req.headers.get('x-wisprs-signature') ?? ''; const expected = createHmac('sha256', process.env.WISPRS_WEBHOOK_SECRET!) .update(body) .digest('hex'); if (!timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) { return new Response('Forbidden', { status: 403 }); } const event = JSON.parse(body); // handle event... return new Response('OK'); }

Event payload

json
{ "event": "transcription.completed", "jobId": 42, "transcriptionId": 99, "status": "completed", "timestamp": "2026-06-17T10:00:00.000Z" }

Retry behaviour

Wisprs retries failed deliveries 3 times with exponential backoff (~1s, ~5s, ~30s). A delivery is considered failed if your endpoint returns a non-2xx status or times out after 10 seconds.

Test a webhook

await client.webhooks.test({ url: 'https://your-app.com/webhooks/wisprs', });

FAQ

Are failed webhook deliveries retried automatically?

Yes. If your endpoint returns a non-2xx status or times out after 10 seconds, Wisprs retries the delivery 3 times with exponential backoff (~1s, ~5s, ~30s). After all retries are exhausted the delivery is marked as failed.

How do I verify that a webhook came from Wisprs?

Every delivery includes an x-wisprs-signature header. Compute an HMAC-SHA256 of the raw request body using your signing secret and compare it using a constant-time comparison. The example above shows the full verification pattern.

Can I receive webhooks for specific events only?

Currently all endpoints receive transcription.completed and transcription.failed events. Per-event filtering is on the roadmap.