A webhook sends your server a request every time a run changes state. It is the simplest way to keep another system in step with Kestrel.
Add an endpoint
Under Settings, Webhooks, add a URL and choose the events you want. Kestrel sends a test event straight away so you can check that it arrives.
Events
run.resolvedwhen a ticket is closed.run.waitingwhen Kestrel asks a person.run.handed_overwhen a ticket goes to your team.rule.changedwhen someone edits a rule.
What a request looks like
{ "event": "run.waiting", "run": "run_48214", "ticket": "81226", "category": "refunds", "asked": { "amount": 34000, "currency": "usd", "over_limit_by": 14000 }}Check the signature
Every request carries a Kestrel-Signature header. Compare it with a hash of the body made with your endpoint's secret, and ignore any request that does not match.
import { createHmac, timingSafeEqual } from 'node:crypto' export function isFromKestrel(body: string, signature: string, secret: string) { const expected = createHmac('sha256', secret).update(body).digest('hex') return timingSafeEqual(Buffer.from(expected), Buffer.from(signature))}Retries
Answer with a 2xx status within ten seconds. If you do not, Kestrel tries again six times over a day, waiting longer each time. Each event has an id, so you can ignore one you have already handled.