WEBHOOKS
Webhooks
Portfolwright delivers signed event payloads via HTTP POST to your endpoint. Configure your webhook URL in the dashboard.
Event types
| Event | Trigger |
|---|---|
drift.detected | Position drifts beyond configured threshold (before plan creation) |
rebalance.plan_ready | Rebalance plan computed and ready for execution |
rebalance.executing | Plan confirmed and orders submitted to exchange |
order.filled | Individual exchange order receives a fill (may fire multiple times per order) |
rebalance.complete | All orders in the plan have been fully filled |
rebalance.failed | Exchange rejection, connectivity failure, or cost_budget exceeded |
drift.detected
{
"event": "drift.detected",
"portfolio_id": "pf_77423_a8c4",
"max_drift": 0.047,
"breached_isin": "IE00B4L5Y983",
"timestamp": "2025-01-03T09:14:02Z"
}
rebalance.plan_ready
{
"event": "rebalance.plan_ready",
"rebalance_id": "rb_20250103_a7c2",
"portfolio_id": "pf_77423_a8c4",
"order_count": 3,
"estimated_cost_eur": 451.20,
"timestamp": "2025-01-03T09:14:14Z"
}
order.filled
{
"event": "order.filled",
"rebalance_id": "rb_20250103_a7c2",
"order_id": "ord_XAMS_0041",
"isin": "IE00B4L5Y983",
"side": "buy",
"fill_quantity": 6.2500,
"fill_price_eur": 72.11,
"exchange": "XAMS",
"timestamp": "2025-01-03T09:17:33Z"
}
Signature verification
Each request includes a Pwt-Signature header. Verify with HMAC-SHA256 using your endpoint signing key (separate from your API key, found in the dashboard).
import hmac, hashlib
def verify_signature(payload_bytes, signature_header, signing_key):
"""Verify Pwt-Signature header."""
expected = hmac.new(
signing_key.encode(), payload_bytes, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
Respond with HTTP 200 to acknowledge. Portfolwright retries failed deliveries up to 5 times with exponential backoff (1s, 2s, 4s, 8s, 16s).