Webhooks
Receive real-time HTTP notifications when events occur in your Daily AI Agent OS account.
How Webhooks Work
When an event occurs (like a new signal being generated), Daily AI Agent OS sends an HTTP POST request to your configured endpoint with the event payload. Your server processes the event and returns a 200 response to acknowledge receipt.
To register a webhook, make a POST request to /v1/webhooks with your endpoint URL and the events you want to subscribe to:
curl -X POST https://api.dailyai.dev/v1/webhooks \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/dailyai",
"events": ["signal.created", "agent.completed"],
"secret": "whsec_your_secret_key"
}'
Supported Events
Subscribe to any combination of the following event types:
| Event | Trigger | Description |
|---|---|---|
| signal.created | New signal | Fired when an agent generates a new trading or analysis signal |
| signal.updated | Signal change | Fired when a signal's status changes (e.g., confidence updated) |
| signal.closed | Signal closed | Fired when a signal reaches its take-profit, stop-loss, or expires |
| agent.started | Agent begins | Fired when an agent begins executing a run |
| agent.completed | Agent finishes | Fired when an agent completes a run successfully |
| agent.error | Agent error | Fired when an agent encounters an error during execution |
| webhook.test | Manual test | Fired when you trigger a test event from the dashboard |
Payload Format
All webhook payloads follow a consistent envelope format. The data field contains the event-specific payload.
Common Envelope
{
"id": "evt_abc123def456",
"type": "signal.created",
"api_version": "2026-03-01",
"created_at": "2026-03-25T14:30:00Z",
"data": { ... }
}
signal.created
{
"id": "evt_sig_001",
"type": "signal.created",
"api_version": "2026-03-01",
"created_at": "2026-03-25T14:30:00Z",
"data": {
"signal_id": "sig_abc123",
"agent_id": "trading",
"asset": "AAPL",
"strategy": "momentum",
"direction": "long",
"confidence": 0.87,
"entry_price": 198.45,
"stop_loss": 195.20,
"take_profit": 204.10,
"metadata": {
"indicators": ["RSI", "MACD", "EMA_20"],
"reasoning": "Strong momentum with RSI at 65 and MACD crossover"
}
}
}
signal.closed
{
"id": "evt_sig_002",
"type": "signal.closed",
"api_version": "2026-03-01",
"created_at": "2026-03-25T18:45:00Z",
"data": {
"signal_id": "sig_abc123",
"asset": "AAPL",
"close_reason": "take_profit",
"entry_price": 198.45,
"exit_price": 204.10,
"pnl_percent": 2.85,
"pnl_absolute": 5.65,
"duration_minutes": 255
}
}
agent.error
{
"id": "evt_err_001",
"type": "agent.error",
"api_version": "2026-03-01",
"created_at": "2026-03-25T16:00:00Z",
"data": {
"agent_id": "trading",
"run_id": "run_xyz789",
"error_code": "DATA_UNAVAILABLE",
"message": "Market data provider returned empty response for AAPL",
"retryable": true
}
}
Signature Verification
Every webhook request includes an X-DailyAI-Signature header containing an HMAC-SHA256 signature of the request body. Always verify this signature to ensure the request genuinely came from Daily AI Agent OS.
How to Verify
Compute an HMAC-SHA256 hash of the raw request body using your webhook secret, then compare it to the signature in the header.
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
"""Verify the webhook signature.
Args:
payload: Raw request body bytes
signature: Value of the X-DailyAI-Signature header
secret: Your webhook signing secret (whsec_...)
Returns:
True if the signature is valid
"""
expected = hmac.new(
secret.encode("utf-8"),
payload,
hashlib.sha256
).hexdigest()
expected_sig = f"sha256={expected}"
return hmac.compare_digest(expected_sig, signature)
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
const expectedSig = `sha256=${expected}`;
return crypto.timingSafeEqual(
Buffer.from(expectedSig),
Buffer.from(signature)
);
}
Request Headers
| Header | Description |
|---|---|
| X-DailyAI-Signature | HMAC-SHA256 signature: sha256=abc123... |
| X-DailyAI-Event | Event type (e.g., signal.created) |
| X-DailyAI-Delivery | Unique delivery ID for deduplication |
| X-DailyAI-Timestamp | Unix timestamp of when the event was sent |
| Content-Type | Always application/json |
Retry Policy
If your endpoint returns a non-2xx response or times out, Daily AI Agent OS will retry the delivery using exponential backoff:
| Attempt | Delay | Total Elapsed |
|---|---|---|
| 1st retry | 30 seconds | 30 seconds |
| 2nd retry | 2 minutes | 2.5 minutes |
| 3rd retry | 10 minutes | 12.5 minutes |
| 4th retry | 30 minutes | 42.5 minutes |
| 5th retry | 2 hours | ~2.7 hours |
| 6th retry (final) | 8 hours | ~10.7 hours |
After 6 failed attempts, the delivery is marked as failed. You can view failed deliveries and manually retry them from the dashboard under Settings → Webhooks → Deliveries.
If your endpoint fails consistently for 72 hours, the webhook will be automatically disabled and you'll receive an email notification.
Testing Webhooks Locally
Use ngrok to expose your local development server to the internet for webhook testing.
Step 1: Start your local server
# Start your webhook receiver (e.g., on port 3000)
node webhook_receiver.js
# or
python webhook_server.py
Step 2: Start ngrok
ngrok http 3000
ngrok will display a public URL like https://abc123.ngrok.io.
Step 3: Register the webhook
curl -X POST https://api.dailyai.dev/v1/webhooks \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://abc123.ngrok.io/webhooks/dailyai",
"events": ["signal.created", "agent.completed"],
"secret": "whsec_test_secret_123"
}'
Step 4: Trigger a test event
# Send a test ping from the API
curl -X POST https://api.dailyai.dev/v1/webhooks/whk_your_id/test \
-H "Authorization: Bearer sk-your-key"
You should see the test event appear in your local server logs and in the ngrok dashboard at http://localhost:4040.