Webhooks
Webhooks notify your server when events occur on your experiments.
Configuring Webhooks
Include webhook preferences in your experiment submission:
{
"communication_preferences": {
"webhook_url": "https://your-server.com/litmus/webhook",
"notification_events": ["claimed", "started", "completed", "issue"]
}
}Event Types
| Event | Description |
|---|---|
claimed | Operator has claimed the job |
started | Operator has started work |
completed | Results have been submitted |
issue | Operator reported an issue |
approved | Results were approved |
disputed | Results were disputed |
Webhook Payload
{
"event": "completed",
"experiment_id": "exp_abc123",
"timestamp": "2026-02-05T14:00:00Z",
"data": {
"status": "pending_approval",
"results_available": true
}
}Signature Verification
All webhooks are signed using HMAC-SHA256. Verify the signature to ensure authenticity:
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)The signature is in the X-Litmus-Signature header.
Test Webhook
POST /webhooks/testSend a test webhook to verify your endpoint.
Request Body
{
"url": "https://your-server.com/litmus/webhook",
"event_type": "completed"
}Response
{
"success": true,
"response_code": 200,
"response_time_ms": 142
}Retry Policy
Failed webhooks are retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
After 5 failures, webhook delivery is paused and you'll receive an email notification.
Best Practices
- Respond quickly — Return 200 within 5 seconds; process asynchronously
- Handle duplicates — Webhooks may be retried; use idempotency keys
- Verify signatures — Always validate the HMAC signature
- Use HTTPS — Webhook URLs must use HTTPS