Event types
| Event | Triggered when |
|---|---|
compute_complete | A /compute/* job finishes |
usage_alert | Account hits 50%, 80%, or 100% of monthly quota |
limit_reached | Daily operation limit reached |
budget_alert | Monthly spend hits the user-set threshold |
key_created | An FHE key is generated or uploaded |
key_deleted | An FHE key is deleted |
key_rotated | An API key is rotated (24 h grace) |
invoice_created | Stripe issues an invoice |
invoice_paid | Stripe confirms payment |
invoice_failed | Stripe payment fails |
events array to receive all.
POST /api/v1/webhooks
Register a webhook endpoint.
Auth: WRITE+
Request
| Field | Type | Required | Notes |
|---|---|---|---|
url | string | Yes | HTTPS only, ≤2048 chars, public IP only |
events | array<string> | No | Empty = all events |
secret | string | No | ≥32 chars; auto-generated if omitted |
localhost,127.0.0.0/8,::1.local,.internal,.intranetTLDs- Private IPv4 ranges:
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 - Link-local, loopback, reserved ranges
Response — 201 Created
secret was omitted in the request, a generated secret is returned in
this response once only.
GET /api/v1/webhooks
List registered webhooks.
Auth: Public (any valid key)
Request
Response — 200 OK
GET /api/v1/webhooks/{webhook_id}
Get details for one webhook.
Auth: Public
Response — 200 OK
PATCH /api/v1/webhooks/{webhook_id}
Update URL or event subscriptions.
Auth: WRITE+
Request
Response — 200 OK
Returns the full updated webhook object.PATCH /api/v1/webhooks/{webhook_id}/regenerate-secret
Rotate the HMAC secret. The new secret is shown once only.
Auth: WRITE+
Response — 200 OK
DELETE /api/v1/webhooks/{webhook_id}
Unregister a webhook.
Auth: WRITE+
Response — 200 OK
POST /api/v1/webhooks/test
Send a synthetic test event to all registered webhooks. Useful for verifying
your verifier and HTTP plumbing.
Auth: Public
Request
Response — 200 OK
GET /api/v1/webhooks/events
Recent webhook delivery history (across all webhooks).
Auth: Public
Request
Response — 200 OK
GET /api/v1/webhooks/{webhook_id}/deliveries
Per-webhook delivery history.
Auth: Public
Response — 200 OK
POST /api/v1/webhooks/{webhook_id}/deliveries/{delivery_id}/replay
Replay a previously failed delivery. Idempotent — replaying a successful
delivery is a no-op.
Auth: WRITE+
Response — 200 OK
Webhook payload format
WAVIS sends every delivery as a JSONPOST to your URL:
data field varies per event type — see schemas below.
Verifying signatures
TheX-WAVIS-Signature header is sha256=<hex> where the hex is HMAC-SHA256
of the raw request body using your shared secret.
Python (Flask)
Node.js (Express)
hmac.compare_digest /
timingSafeEqual) — == leaks info via timing.
Retry policy
Failed deliveries (HTTP 5xx, timeout, connection error) are retried with exponential backoff:| Attempt | Wait |
|---|---|
| 1 | immediate |
| 2 | 30 s |
| 3 | 5 min |
| 4 | give up |
failed and not retried
automatically. Use POST /webhooks/{id}/deliveries/{delivery_id}/replay to
retry manually.
HTTP 4xx responses are NOT retried. Treat 401/404 as permanent failure
on your side.
Idempotency: the delivery_id is unique per attempt set; if you receive
the same delivery_id twice, it’s a retry of the same logical event.
Per-event payloads
compute_complete
usage_alert
key_rotated
invoice_paid
Best practices
- Verify the signature on every request. Drop unsigned requests at the load balancer if possible.
- Respond within 5 s. Long-running work should be queued and acknowledged immediately with
200 OK. - Handle replays. Use
delivery_idas the idempotency key in your downstream system. - Use a separate endpoint per environment. Keeps
wvs_test_*events out of production webhooks. - Rotate the secret quarterly. WAVIS doesn’t enforce it; your security policy should.
- Subscribe narrowly. Only the events you actually use — reduces load and noise.
Next Steps
Billing API
Subscription and invoice events
Compute API
The job_ids that webhook events reference