Webhooks
Public API availability for webhook management
Webhook endpoint management is not currently exposed through the API-key-authenticated
/api/v1 surface. Keva's webhook configuration routes are dashboard routes with
interactive user authorization; they must not be called with a keva_live_ API key.
Do not assume a webhook event is delivered until the relevant producer, durable delivery state, deployed endpoint, and independent recipient read-back have all been proven.
The current locally dispatchable outbound catalogue is exactly ticket.created, approval.created, approval.decided, and approval.expired. New or event-changing
configuration rejects other event names. Existing historical endpoint rows remain
readable and can still be disabled or deleted; their older subscriptions are not proof
that those events can be delivered.
Receiving an account webhook
Keva sends a POST request with a JSON body to each active endpoint subscribed to the
event. Verify the signature before parsing the body: compute HMAC-SHA256 with the
endpoint's signing secret over the exact raw JSON bytes sent in the request body, then
encode the digest as lowercase hexadecimal. Compare that value with
X-Keva-Signature; it has no sha256= prefix.
The request includes these headers:
X-Keva-Signature— the lowercase hexadecimal HMAC-SHA256 digest.X-Keva-Event— the event type, matching the payload'seventfield.X-Keva-Event-Id— the payload's stable event ID, matching itsidfield.
Use the stable event ID as an idempotency key and deduplicate before applying side effects. Delivery is at least once: a receiver can see the same event again, so return a success response only after the event is safely accepted or processed idempotently.
Keva treats any 2xx response as delivered. It never follows redirects: every 3xx
response is refused as a redirect and is terminal. Other 4xx responses are terminal;
408 and 429 are retried. 5xx responses and transport failures are also retried,
for up to three delivery attempts in total. A retryable failure that remains after the
final attempt is recorded as a failed delivery.
The current protocol has no timestamp header or enforced replay window. Although the
JSON payload contains a timestamp, it is not a replay-protection guarantee; use the
event ID and your own retention policy for replay handling.
The four supported event types are ticket.created, approval.created,
approval.decided, and approval.expired.