Šis puslapis dar neišverstas, todėl rodomas angliškai.
Webhooks
ORYVOX sends signed webhooks to endpoints you add in the dashboard under
ORYVOX sends signed webhooks to endpoints you add in the dashboard under
Core > Observability > Incidents & alerts (/app/core/monitoring), in the webhooks list.
The URL must be a public https:// address; internal and private network addresses are refused.
Each endpoint gets its own signing secret (whsec_...), shown once when you add it. An endpoint
receives every public event, or only the types you pick. Send test delivers a test.ping
(always delivered, whatever the filter).
Events
| Type | When |
|---|---|
security.alert | A warning or critical security event: blocked or masked secrets, blocked personal data, denied IPs, scope denials, rate-limit hits, new key IPs, budget stops, sign-in and policy events. At most once per type every 15 minutes. |
incident.opened | An alert rule or the automatic watch opened an incident (error rate, latency, provider trouble...). |
incident.resolved | That incident is resolved. |
budget.warning | A project's daily or monthly spend reached its warning level (budget_warn_at, default 80%). |
budget.exceeded | A project's spend reached 100% of its budget. |
credits.low | The credit balance fell below your low-balance threshold. |
credits.exhausted | The balance reached zero; prepaid requests now fail with 402 insufficient_credits. |
invoice.created | A monthly invoice was issued. |
invoice.paid | An invoice was paid. |
invoice.failed | A payment failed. |
test.ping | Sent by Send test. |
Payload
{
"id": "evt_k2j4...",
"type": "budget.warning",
"version": 1,
"created": 1790000000,
"data": {"project": "Support bot", "project_id": 12, "period": "month", "budget": 500.0, "spent": 412.37}
}version is the event schema version. data depends on the type; budget amounts are in
charged USD.
Signature
Every request has an Oryvox-Signature header:
Oryvox-Signature: t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bdtis the Unix time the request was signed.v1is the hex HMAC-SHA256 of"{t}.{raw_body}"keyed with the endpoint secret.
To verify: recompute the HMAC over the raw body, compare in constant time, and reject
timestamps older than 5 minutes (replay protection). The header carries one v1 value; the
SDK verifiers also accept several (any match passes).
The SDKs do all of this:
import Oryvox from '@oryvox/sdk';
app.post('/webhooks/oryvox', express.raw({ type: 'application/json' }), (req, res) => {
let event;
try {
event = Oryvox.webhooks.verify(req.body, req.header('Oryvox-Signature'), process.env.ORYVOX_WEBHOOK_SECRET!);
} catch {
return res.sendStatus(400);
}
handle(event); // event.id, event.type, event.version, event.created, event.data
res.sendStatus(200);
});from oryvox import Oryvox, WebhookVerificationError
try:
event = Oryvox.webhooks.verify(raw_body, headers["Oryvox-Signature"], WEBHOOK_SECRET)
except WebhookVerificationError:
return 400The optional last argument sets the tolerance in seconds (default 300).
Manual verification (any language):
import hashlib, hmac, time
def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t = parts["t"]
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - int(t)) <= toleranceDelivery and retries
- Respond with any
2xxwithin 10 seconds. Do slow work asynchronously. - Anything else (another status, a timeout, a connection error) is retried, up to 8 attempts in total, with exponential backoff: 30 s, 2 min, 8 min, 32 min, about 2 h, then 6 h (the cap), so the last attempt is about 15 hours after the first.
- After the last failed attempt the delivery is marked failed. The webhooks list shows each endpoint's last status and delivery time.
- Delivery is at least once: the same event can arrive more than once, and events can
arrive out of order. Deduplicate by
event.idand usecreatedto order them.