* feat(rooms): add webhook notifications for transcript completion
- Add webhook_url and webhook_secret fields to rooms table
- Create Celery task with 24-hour retry window using exponential backoff
- Send transcript metadata, diarized text, topics, and summaries via webhook
- Add HMAC signature verification for webhook security
- Add test endpoint POST /v1/rooms/{room_id}/webhook/test
- Update frontend with webhook configuration UI and test button
- Auto-generate webhook secret if not provided
- Trigger webhook after successful file pipeline processing for room recordings
* style: linting
* fix: remove unwanted files
* fix: update openapi gen
* fix: self-review
* docs: add comprehensive webhook documentation
- Document webhook configuration, events, and payloads
- Include transcript.completed and test event examples
- Add security considerations and best practices
- Provide example webhook receiver implementation
- Document retry policy and signature verification
* fix: remove audio_mp3_url from webhook payload
- Remove audio download URL generation from webhook
- Update documentation to reflect the change
- Keep only frontend_url for accessing transcripts
* docs: remove unwanted section
* fix: correct API method name and type imports for rooms
- Fix v1RoomsRetrieve to v1RoomsGet
- Update Room type to RoomDetails throughout frontend
- Fix type imports in useRoomList, RoomList, RoomTable, and RoomCards
* feat: add show/hide toggle for webhook secret field
- Add eye icon button to reveal/hide webhook secret when editing
- Show password dots when webhook secret is hidden
- Reset visibility state when opening/closing dialog
- Only show toggle button when editing existing room with secret
* fix: resolve event loop conflict in webhook test endpoint
- Extract webhook test logic into shared async function
- Call async function directly from FastAPI endpoint
- Keep Celery task wrapper for background processing
- Fixes RuntimeError: event loop already running
* refactor: remove unnecessary Celery task for webhook testing
- Webhook testing is synchronous and provides immediate feedback
- No need for background processing via Celery
- Keep only the async function called directly from API endpoint
* feat: improve webhook test error messages and display
- Show HTTP status code in error messages
- Parse JSON error responses to extract meaningful messages
- Improved UI layout for webhook test results
- Added colored background for success/error states
- Better text wrapping for long error messages
* docs: adjust doc
* fix: review
* fix: update attempts to match close 24h
* fix: add event_id
* fix: changed to uuid, to have new event_id when reprocess.
* style: linting
* fix: alembic revision
6.9 KiB
Reflector Webhook Documentation
Overview
Reflector supports webhook notifications to notify external systems when transcript processing is completed. Webhooks can be configured per room and are triggered automatically after a transcript is successfully processed.
Configuration
Webhooks are configured at the room level with two fields:
webhook_url: The HTTPS endpoint to receive webhook notificationswebhook_secret: Optional secret key for HMAC signature verification (auto-generated if not provided)
Events
transcript.completed
Triggered when a transcript has been fully processed, including transcription, diarization, summarization, and topic detection.
test
A test event that can be triggered manually to verify webhook configuration.
Webhook Request Format
Headers
All webhook requests include the following headers:
| Header | Description | Example |
|---|---|---|
Content-Type |
Always application/json |
application/json |
User-Agent |
Identifies Reflector as the source | Reflector-Webhook/1.0 |
X-Webhook-Event |
The event type | transcript.completed or test |
X-Webhook-Retry |
Current retry attempt number | 0, 1, 2... |
X-Webhook-Signature |
HMAC signature (if secret configured) | t=1735306800,v1=abc123... |
Signature Verification
If a webhook secret is configured, Reflector includes an HMAC-SHA256 signature in the X-Webhook-Signature header to verify the webhook authenticity.
The signature format is: t={timestamp},v1={signature}
To verify the signature:
- Extract the timestamp and signature from the header
- Create the signed payload:
{timestamp}.{request_body} - Compute HMAC-SHA256 of the signed payload using your webhook secret
- Compare the computed signature with the received signature
Example verification (Python):
import hmac
import hashlib
def verify_webhook_signature(payload: bytes, signature_header: str, secret: str) -> bool:
# Parse header: "t=1735306800,v1=abc123..."
parts = dict(part.split("=") for part in signature_header.split(","))
timestamp = parts["t"]
received_signature = parts["v1"]
# Create signed payload
signed_payload = f"{timestamp}.{payload.decode('utf-8')}"
# Compute expected signature
expected_signature = hmac.new(
secret.encode("utf-8"),
signed_payload.encode("utf-8"),
hashlib.sha256
).hexdigest()
# Compare signatures
return hmac.compare_digest(expected_signature, received_signature)
Event Payloads
transcript.completed Event
This event includes a convenient URL for accessing the transcript:
frontend_url: Direct link to view the transcript in the web interface
{
"event": "transcript.completed",
"event_id": "transcript.completed-abc-123-def-456",
"timestamp": "2025-08-27T12:34:56.789012Z",
"transcript": {
"id": "abc-123-def-456",
"room_id": "room-789",
"created_at": "2025-08-27T12:00:00Z",
"duration": 1800.5,
"title": "Q3 Product Planning Meeting",
"short_summary": "Team discussed Q3 product roadmap, prioritizing mobile app features and API improvements.",
"long_summary": "The product team met to finalize the Q3 roadmap. Key decisions included...",
"webvtt": "WEBVTT\n\n00:00:00.000 --> 00:00:05.000\n<v Speaker 1>Welcome everyone to today's meeting...",
"topics": [
{
"title": "Introduction and Agenda",
"summary": "Meeting kickoff with agenda review",
"timestamp": 0.0,
"duration": 120.0,
"webvtt": "WEBVTT\n\n00:00:00.000 --> 00:00:05.000\n<v Speaker 1>Welcome everyone..."
},
{
"title": "Mobile App Features Discussion",
"summary": "Team reviewed proposed mobile app features for Q3",
"timestamp": 120.0,
"duration": 600.0,
"webvtt": "WEBVTT\n\n00:02:00.000 --> 00:02:10.000\n<v Speaker 2>Let's talk about the mobile app..."
}
],
"participants": [
{
"id": "participant-1",
"name": "John Doe",
"speaker": "Speaker 1"
},
{
"id": "participant-2",
"name": "Jane Smith",
"speaker": "Speaker 2"
}
],
"source_language": "en",
"target_language": "en",
"status": "completed",
"frontend_url": "https://app.reflector.com/transcripts/abc-123-def-456"
},
"room": {
"id": "room-789",
"name": "Product Team Room"
}
}
test Event
{
"event": "test",
"event_id": "test.2025-08-27T12:34:56.789012Z",
"timestamp": "2025-08-27T12:34:56.789012Z",
"message": "This is a test webhook from Reflector",
"room": {
"id": "room-789",
"name": "Product Team Room"
}
}
Retry Policy
Webhooks are delivered with automatic retry logic to handle transient failures. When a webhook delivery fails due to server errors or network issues, Reflector will automatically retry the delivery multiple times over an extended period.
Retry Mechanism
Reflector implements an exponential backoff strategy for webhook retries:
- Initial retry delay: 60 seconds after the first failure
- Exponential backoff: Each subsequent retry waits approximately twice as long as the previous one
- Maximum retry interval: 1 hour (backoff is capped at this duration)
- Maximum retry attempts: 30 attempts total
- Total retry duration: Retries continue for approximately 24 hours
How Retries Work
When a webhook fails, Reflector will:
- Wait 60 seconds, then retry (attempt #1)
- If it fails again, wait ~2 minutes, then retry (attempt #2)
- Continue doubling the wait time up to a maximum of 1 hour between attempts
- Keep retrying at 1-hour intervals until successful or 30 attempts are exhausted
The X-Webhook-Retry header indicates the current retry attempt number (0 for the initial attempt, 1 for first retry, etc.), allowing your endpoint to track retry attempts.
Retry Behavior by HTTP Status Code
| Status Code | Behavior |
|---|---|
| 2xx (Success) | No retry, webhook marked as delivered |
| 4xx (Client Error) | No retry, request is considered permanently failed |
| 5xx (Server Error) | Automatic retry with exponential backoff |
| Network/Timeout Error | Automatic retry with exponential backoff |
Important Notes:
- Webhooks timeout after 30 seconds. If your endpoint takes longer to respond, it will be considered a timeout error and retried.
- During the retry period (~24 hours), you may receive the same webhook multiple times if your endpoint experiences intermittent failures.
- There is no mechanism to manually retry failed webhooks after the retry period expires.
Testing Webhooks
You can test your webhook configuration before processing transcripts:
POST /v1/rooms/{room_id}/webhook/test
Response:
{
"success": true,
"status_code": 200,
"message": "Webhook test successful",
"response_preview": "OK"
}
Or in case of failure:
{
"success": false,
"error": "Webhook request timed out (10 seconds)"
}