A webhook is an HTTP call out to your stack when something happens in chat — a qualified lead, an escalation, a customer matching a rule. There are two ways to fire one from an agent.
Option 1 — The built-in webhook_trigger tool
Turn on the webhook_trigger built-in under Tools & Actions and supply a destination URL. The agent decides when to call it and what JSON to send.
Use this when you want the model to choose the moment — e.g. fire a webhook to your analytics endpoint when intent X is detected.
Option 2 — A custom action with fetch
Full control. Write a custom action with a webhook credential and post anything you want:
const payload = {
event: 'lead.captured',
source: 'chat',
customer: params.email,
conversation_id: params.conversation_id,
timestamp: new Date().toISOString(),
};
const r = await fetch(credentials.webhook_url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(credentials.secret ? { 'X-Webhook-Secret': credentials.secret } : {}),
},
body: JSON.stringify(payload),
});
if (!r.ok) throw new Error(`Webhook ${r.status}`);
return { success: true };See Build a custom action for the full code contract.
Test endpoints to develop against
While building, point the webhook at one of these to inspect the payload:
- webhook.site — free, instant, no signup. Gives you a random URL and shows every request that hits it.
- requestbin.com — similar; useful when you need to share the URL with a teammate.
Securing the receiving endpoint
Your receiver should reject calls that aren't from chatzuri. Two common patterns:
- Shared secret — add a long random string to the
secretfield on the webhook credential. The custom action sends it asX-Webhook-Secret; your receiver verifies it matches. - HMAC signature — sign the body with a secret using
crypto.subtle(in your custom action) and verify the signature in your receiver.
Retries and idempotency
Webhook calls are not automatically retried by chatzuri. If your endpoint is briefly down, the action returns an error to the agent. Build retries into your receiver or accept that an occasional event may be missed.
For events you cannot afford to lose, write them to a queue (Postgres outbox table, Kafka, SQS) from your receiver and process asynchronously.
Inverse direction — receiving webhooks into chatzuri
Channel webhooks (Stripe payment events, WhatsApp inbound messages, Mailgun email replies, etc.) route into chatzuri via POST /api/v1/agents/[agentId]/chat/[channel]. See Channels overview for the list of channels with built-in inbound webhooks.
