Webhooks
Portfolwright sends HTTPS POST requests to your endpoint for each event. Payloads are signed with HMAC-SHA256 using your webhook secret.
Rebalance events
Three events fire for each rebalance lifecycle.
rebalance.calculated
{
"event": "rebalance.calculated",
"id": "evt_4m2p9n",
"created": 1750512600,
"data": {
"rebalance_id": "rb_7z4n9q",
"portfolio_id": "pf_3x8k2m",
"orders_pending": 3,
"exchanges": ["XEUR", "XETR"],
"estimated_tax_impact_eur": -312.40
}
}
rebalance.completed
{
"event": "rebalance.completed",
"id": "evt_4m2p9r",
"created": 1750512734,
"data": {
"rebalance_id": "rb_7z4n9q",
"portfolio_id": "pf_3x8k2m",
"orders_placed": 3,
"orders_filled": 3,
"tax_impact_eur": -312.40,
"mifid_record_ids": ["mf_8k3p1r", "mf_8k3p1s", "mf_8k3p1t"]
}
}
Signature verification
Every webhook delivery includes a Portfolwright-Signature header. Verify it before processing.
HMAC-SHA256 verification (Node.js)
const crypto = require("crypto");
function verifyWebhook(payload, sigHeader, secret) {
const [ts, sig] = sigHeader.split(",");
const hmac = crypto.createHmac("sha256", secret);
hmac.update(ts + "." + payload);
const expected = hmac.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(sig), Buffer.from(expected)
);
}
Retry behavior
If your endpoint returns any non-2xx status, Portfolwright retries with exponential backoff over 72 hours. Retry schedule: 5s → 30s → 2m → 10m → 1h → 6h → 24h → 72h. After 8 attempts, the delivery is marked failed and visible in your webhook event log.
Your endpoint must respond within 30 seconds. Return 200 as soon as possible — process the event asynchronously. Returning 200 idempotently for duplicate events (same event id) is safe and expected.
Back to docs home →