Webhooks
Upvera can call your server when your startup's Upvera Value moves by at least your threshold. Webhooks are part of the Scale plan. Add up to three HTTPS endpoints in Upvera under Connections › Value API.
Events
| Event | When |
|---|---|
value.threshold | The value moved by at least your threshold (0.1% to 50%) since the last notification, in the direction you chose: up, down or both. Checked every 5 minutes. |
ping | You added an endpoint or pressed Send test. |
The anchor moves on every threshold crossing in either direction, so you get one event per move, not a stream.
Payload
json
{
"v": "upvera/webhook/v1",
"id": "evt_…",
"type": "value.threshold",
"created_at": "2026-10-19T00:05:02Z",
"data": {
"startup": { "slug": "upvera-mthgaif7", "name": "Upvera", "url": "https://app.upvera.co/value/upvera-mthgaif7" },
"value": 344.762011,
"from": 341.213023,
"change_pct": 1.04,
"direction": "up",
"threshold_pct": 1.0,
"as_of": "2026-10-19T00:00:00Z",
"from_at": "2026-10-18T21:00:00Z",
"rule": "value@1"
}
}change_pct is computed by Upvera. Show it as it is.
Headers
text
Upvera-Signature: t=1760834702,v1=5f2b…
Upvera-Event: value.threshold
Upvera-Event-Id: evt_…
Upvera-Delivery-Attempt: 1
User-Agent: Upvera-Webhooks/1.0Verify the signature
v1 is the hex HMAC-SHA256 of t + "." + raw body, keyed with your endpoint's secret (whsec_…). While you rotate a secret, the header carries two v1 values: accept the request if either matches. Reject timestamps older than 5 minutes. Verify before you parse the body.
js
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyUpvera(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.groupBy(header.split(','), (p) => p.split('=')[0]);
const t = Number(parts.t?.[0]?.split('=')[1]);
if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const want = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
return (parts.v1 ?? []).some((p) => {
const got = Buffer.from(p.slice(3), 'hex');
return got.length === want.length && timingSafeEqual(got, want);
});
}Delivery
- At least once. The same event can arrive twice: deduplicate on
id, which is also theUpvera-Event-Idheader. - Any
2xxacknowledges it. Anything else is retried with back-off from 1 minute to 6 hours, 12 attempts in about a day. - HTTPS only, redirects are not followed, the response body is never read, and a delivery times out after 8 seconds.
GET /api/v1/me/deliveriesshows recent deliveries with their status, without bodies.
Updated 2026-10-19