API Reference

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's event field.
  • X-Keva-Event-Id — the payload's stable event ID, matching its id field.

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.