Webhooks let you receive HTTP POST notifications when a job finishes. Instead of polling the Get Job Status endpoint, configure a webhook URL on your portal and get notified automatically.
Setup
1. Generate a signing key
Go to API Keys > Webhook Key in the dashboard and click Generate Webhook Key. Copy the secret — it’s only shown once.
You can also rotate or revoke the key from the same page.
2. Set a webhook URL on your portal
Add a webhook_url when creating or updating a portal:
curl -X PATCH https://agent.usedari.com/portals/my-org/insurance_quote \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"webhook_url": "https://example.com/webhooks/dari"}'
Or set it in the dashboard under Automations > Settings > Webhook URL.
Payload
When a job completes or fails, a POST request is sent to the webhook URL. The payload matches the Get Job Status response with two additional fields:
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"portal_id": "my-org/insurance_quote",
"status": "completed",
"event_type": "completed",
"result": null,
"final_result": {"quoteId": "Q-123", "premium": 89.50},
"error": null,
"total_cost_usd": 0.12,
"downloads_link": "https://storage.example.com/downloads/...",
"video_recording_url": "https://storage.example.com/recordings/...",
"log_url": "logs/550e8400.log",
"created_at": "2025-01-15T10:30:00+00:00",
"updated_at": "2025-01-15T10:31:45+00:00",
"timestamp": "2025-01-15T10:31:45.123456+00:00"
}
| Field | Description |
|---|
event_type | Either completed or error |
timestamp | ISO 8601 timestamp of when the webhook was sent |
All other fields are identical to the job status response.
Signature verification
Every webhook request includes an X-Webhook-Signature header containing an HMAC-SHA256 signature. Verify it to ensure the payload was sent by Dari and hasn’t been tampered with.
The signature is computed over the JSON body using your webhook signing key:
import hashlib
import hmac
import json
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
"""Verify the X-Webhook-Signature header."""
# The payload is serialized with compact separators and sorted keys
payload = json.loads(body)
canonical = json.dumps(payload, separators=(",", ":"), sort_keys=True)
expected = hmac.new(
secret.encode(), canonical.encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
const crypto = require("crypto");
function verifySignature(body, signature, secret) {
const payload = JSON.parse(body);
const canonical = JSON.stringify(payload, Object.keys(payload).sort());
// For exact match, use compact JSON with sorted keys:
const sorted = JSON.stringify(
JSON.parse(body),
Object.keys(JSON.parse(body)).sort()
);
const expected = crypto
.createHmac("sha256", secret)
.update(canonical)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
Always verify the signature before processing the payload. Reject requests with missing or invalid signatures.
Retry behavior
If your endpoint returns a non-2xx status code or times out (10s), the webhook is retried up to 3 times with exponential backoff (1s, 3s, 9s delays).
Requirements
- Your endpoint must return a
2xx status code within 10 seconds
- Both a webhook signing key (org-level) and a webhook URL (portal-level) must be configured for webhooks to fire
- Webhooks are only sent for terminal events (
completed and error)