How it works
- You register a webhook with a URL and the events you care about. Parlay returns a
signing_secret(shown once — store it securely). - When a matching event fires server-side, Parlay POSTs the event JSON to your URL with a signed timestamp header.
- Your endpoint verifies the signature, processes the event, and returns 2xx within 30 seconds.
- If your endpoint is unreachable or returns 5xx, Parlay retries with exponential backoff. Retry schedule: ~1 min, 5 min, 25 min, 2 hr, 8 hr (5 attempts total).
Events
| Event | Fires when | Payload data shape |
|---|---|---|
analysis.completed | An analysis finishes successfully | Full analysis row (same shape as GET /v1/analyses/:id) |
analysis.failed | An analysis fails to complete | Full analysis row with status: "failed" and populated error |
persona.assigned | A persona_assign job completes | { org_id, rep_id, job_id, result } |
methodology.assigned | A methodology_assign job completes | { org_id, rep_id, job_id, result } |
profile.synthesized | A synthesis job completes | { org_id, rep_id, job_id, result } |
playbook.draft.completed | A playbook draft finishes generation | { draft_id, source_count, gemini_input_tokens, gemini_output_tokens, cost_usd_cents } |
playbook.published | A draft is promoted to an active playbook | { playbook_id, draft_id, version } |
insights.generated | An org insights snapshot completes | { org_id, snapshot_id } |
webhook.test | You called the test endpoint | { message, webhook_id, fired_at } |
Register a webhook
signing_secret immediately — there’s no API to retrieve it again. If you lose it, call rotate_webhook_secret to generate a new one.
Receiving and verifying
Each webhook arrives as aPOST with these headers:
| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | parlay-webhook/1 |
X-Parlay-Event | The event name (e.g. analysis.completed) |
X-Parlay-Delivery | UUID of this delivery attempt |
X-Parlay-Signature | t=<unix_timestamp>,v1=<hex_hmac> (Stripe convention) |
analysis.completed example — data is the full analysis row):
Signature verification (TypeScript)
Signature verification (Python)
Test your endpoint
Once registered, you can fire a test event:webhook.test event to your URL. Use this in your local dev (with ngrok or a Cloudflare Tunnel) to confirm signature verification works before going live.
Best practices
Respond fast, process async
Respond fast, process async
Return 2xx within a few seconds. If processing takes longer than that, push the event onto a queue and process it in a background worker. Webhooks that take 30+ seconds will time out and be retried.
Know your runtime's execution limits
Know your runtime's execution limits
Edge and serverless runtimes have short execution windows. If your handler runs heavy work synchronously (audio extraction, AI calls, large DB writes), it can time out before the response is sent.
The safe pattern in every runtime: acknowledge the webhook in the handler, push heavy work to a queue or worker. For audio slicing in particular, the
| Runtime | Typical limit |
|---|---|
| Vercel Functions (Node) | 10s Hobby, 60s Pro |
| Vercel Edge Functions | 25s streaming, 30s total |
| Cloudflare Workers | 30s CPU |
| Supabase Edge Functions | 150s |
| AWS Lambda default | 3s (raise to 15 min) |
| Cloud Run / Render / Fly / Railway | Long-running OK |
ffmpeg_extract recipe shipped on all-day-session segments needs the ffmpeg binary, which most edge runtimes don’t provide. See Backend requirements on the all-day guide for the full breakdown.Make your handler idempotent
Make your handler idempotent
The same event may be delivered more than once (network retries, your endpoint timing out). Use
event.id as a dedupe key in your DB.Verify the signature on every request
Verify the signature on every request
Anyone can POST to your URL. The signature header is what proves it came from Parlay. Reject any request without a valid signature.
Handle event types you don't care about gracefully
Handle event types you don't care about gracefully
If you only listen for
analysis.completed, but Parlay adds analysis.transcribed later, your endpoint will receive both. Switch on event and ignore unknown types — don’t 4xx, that triggers retries.Use multiple webhooks for environment isolation
Use multiple webhooks for environment isolation
Register one webhook for staging (
https://staging.your-app.com/...) and another for production. Both get the same events — your code routes by livemode.Rotating the signing secret
If the secret is ever compromised:signing_secret (only shown once). The old secret stops working immediately. Update your endpoint’s secret first, then rotate, to avoid a brief verification gap.
Pausing without losing config
paused: false.
