Hourzero

Webhooks

Send new leads, conversations, and other agent events to your CRM or automation tools the moment they happen.

A webhook is a message Hourzero sends to another app the moment something happens, like a new lead or a teammate taking over a chat. Use webhooks to add leads to your CRM, alert your team, or start your own automations, without copying anything by hand.

Where to find it: open your agent, go to Settings, and select the Webhooks tab.

How it works

You give Hourzero a web address, called an endpoint, and choose which events it should hear about. Each time one of those events happens, Hourzero sends the details to that address.

  1. 1Something happensA customer leaves their email or starts a chat.
  2. 2Hourzero sends itA signed message goes to your endpoint.
  3. 3Your tool reactsIt adds the lead to your CRM or alerts your team.
  4. 4You check itEvent history shows what was sent and if it arrived.

Webhooks belong to one agent. If you have several agents, set them up on each agent that should send events.

What you can do with webhooks

  • Add every new lead from Acme Support to your CRM, with the name and email the customer typed.
  • Tell your team when a teammate like Maya Chen takes over a conversation, or hands it back to the agent.
  • Copy every message into your own reporting tool.
  • Hear about a data source that couldn't be processed, so you can fix it before customers notice.
  • Keep a record of every time someone publishes the agent.

Before you start

You need an endpoint URL: the web address that should receive the events. It usually comes from one of two places:

  • An automation tool. Many tools, such as Zapier, Make, or n8n, can give you a webhook address that starts a workflow.
  • Your developer, if the events go to your own system. Share the For your developer section with them.

The address must start with https://.

Add an endpoint

  1. Open your agent, go to Settings, and select the Webhooks tab.
  2. Under Webhook endpoints, select Add endpoint. The Add endpoint dialog opens.
  3. Paste the address into Endpoint URL.
  4. Optionally, add a Description, such as "Production CRM". Your list shows it instead of the address, so you can tell endpoints apart.
  5. Choose what to send under Events. Every event starts selected. To pick only a few, select Clear all, then tick the ones you need. Use Search events… to find one by name.
  6. Leave Include playground events off, unless test chats from the Playground should be sent too.
  7. Select Create endpoint.
  8. The Save your signing secret dialog opens. Copy the secret with the copy button, store it somewhere safe, and select I saved it.

The endpoint appears in your list with an Active badge, the number of events it receives, and the last four characters of its secret.

The signing secret is shown only once

The secret lets the receiving side check that a message really came from Hourzero. Give it to whoever set up that side. If you lose it, select Rotate secret to get a new one.

Tip

Send only the events you need. A CRM usually needs Lead created, and maybe Contact identified and Contact updated. Fewer events means less noise in the tool on the other side.

Choose your events

The dialog groups events the same way as the list below. The name in code is what your developer or automation tool sees.

Conversations

EventNameSent when
Conversation createdconversation.createdA new conversation starts.
AI pausedconversation.ai_pausedA teammate takes over a conversation from the agent.
AI resumedconversation.ai_resumedA conversation is handed back to the agent.
Conversation deletedconversation.deletedSomeone permanently deletes a conversation.
Message createdmessage.createdA customer, the agent, or a teammate sends a message.

Contacts and submissions

EventNameSent when
Contact identifiedcontact.identifiedA customer you didn't know yet shares their name, email, or phone number in a form.
Contact updatedcontact.updatedA known contact's details change after they fill in a form.
Lead createdlead.createdA customer submits a Collect leads form.
Submission createdsubmission.createdA customer submits a Collect data or Custom form form.

Agents, knowledge, and channels

EventNameSent when
Agent publishedagent.publishedSomeone publishes the agent to a channel.
Agent rolled backagent.rolled_backSomeone restores an earlier live version.
Data source readydata_source.readyA data source finishes processing and is ready for training.
Data source faileddata_source.failedHourzero can't process a data source.
Deployment activateddeployment.activatedA channel goes live, or its live settings change.
Deployment disableddeployment.disabledA channel stops being live.

The two deployment events arrive together with Agent published or Agent rolled back, one for each channel whose live setup changed.

Some events contain personal details

Message created, both contact events, Lead created, and Submission created include what customers wrote or typed into forms. Only send them to tools you're allowed to store customer data in.

Check that events arrive

The Event history section, below your endpoints, lists this agent's events, newest first. Each row shows the event, its Status, whether it came from Production (real customers) or the Playground, how many endpoints it went to, and when it happened.

The status tells you how delivery went:

  • Delivered: every endpoint accepted it.
  • Processing: Hourzero is still sending it, or waiting to try again.
  • Failed: at least one endpoint didn't accept it, and Hourzero stopped trying.
  • Cancelled: the endpoint was turned off or deleted before delivery.
  • No endpoints: no endpoint was set up for this event when it happened.

Use the filters above the list to show one event type, status, or environment. Select Clear to see everything again.

To look closer, select the eye icon on a row. You see the exact message that was sent under Event payload, each endpoint under Deliveries, and every try under Attempt logs, with the reply code from the other side and how long it took.

Send a test event

Turn on Include playground events for your endpoint, then chat with the agent in the Playground. Conversation created and Message created events appear in Event history within seconds. Turn the setting off again when you're done.

Resend an event

If an event failed because the other tool was down or set up wrong, fix the problem first. Then:

  1. In Event history, select the eye icon on the event.
  2. Under Deliveries, select the endpoint you want to send it to again.
  3. Select Resend. A message confirms "Webhook queued for delivery".

Edit, pause, or delete an endpoint

  • Change events or the address: select Edit, make your changes, and select Save endpoint.
  • Pause deliveries: select Edit, turn off Endpoint active, and save. The badge changes to Disabled. A paused endpoint doesn't receive new events, or events still waiting to be sent.
  • Delete an endpoint: select the trash icon, then Delete endpoint. Events still waiting are cancelled. Past events and their delivery details stay in Event history.

Get a new signing secret

Select Rotate secret on the endpoint. The Save your signing secret dialog shows the new secret once.

The old secret stops working right away

From the next event on, messages are signed with the new secret. Update the receiving side straight away, or it will start rejecting events from Hourzero.

For your developer

This section has the technical details for whoever builds or maintains the receiving side.

Requests

Each event is an HTTP POST with a JSON body and these headers:

HeaderValue
Content-Typeapplication/json; charset=utf-8
Hourzero-Signaturet=<unix timestamp>,v1=<hex signature>
X-Hourzero-Event-IdThe event id
X-Hourzero-Event-TypeThe event type
User-AgentHourzero-Webhooks/1.0

The endpoint URL must use https://, be at most 2,048 characters, and resolve to a public address. URLs with a username, password, or #fragment are rejected, and so are private and local network addresses. Redirects are not followed.

Payload

Every event uses the same envelope. data.object holds the record the event is about, and its shape depends on type. environment is production for real customer activity and playground for test chats.

Here is a lead.created example. The keys inside data.object.data are the field keys of your Collect leads form.

{
  "id": "evt_Qm3c8VfR2kXn7pLs0aTyB1wZ",
  "object": "event",
  "api_version": "2026-09-10",
  "type": "lead.created",
  "created_at": "2026-10-02T09:41:12.000Z",
  "organization_id": "Xr7Kq2mVt9LpA4sD",
  "agent_id": "6f1c2b9e-4d3a-4e8f-9b2a-7c5d1e0f3a21",
  "environment": "production",
  "data": {
    "object": {
      "id": "0c9e4a7b-2f1d-4c6e-8a3b-5d7f9e1c2b40",
      "object": "submission",
      "action_id": "a3d5f7e9-1b2c-4d6e-8f0a-2c4e6a8b0d12",
      "action_key": "a3d5f7e9-1b2c-4d6e-8f0a-2c4e6a8b0d12",
      "action_kind": "collect_leads",
      "conversation_id": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c65",
      "contact_id": "4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8",
      "data": {
        "name": "Jordan Lee",
        "email": "jordan@example.com"
      },
      "created_at": "2026-10-02T09:41:11.000Z"
    }
  }
}

Verify the signature

The v1 value is an HMAC-SHA256, in hex, of the timestamp t, a period, and the raw request body. The key is the full signing secret, including its whsec_ prefix. Reject the request if the signature doesn't match or the timestamp is more than five minutes from your server's clock.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyHourzeroSignature(
  rawBody: string,
  header: string,
  secret: string,
) {
  const values = new Map<string, string[]>();
  for (const part of header.split(",")) {
    const separator = part.indexOf("=");
    if (separator === -1) continue;
    const key = part.slice(0, separator).trim();
    const value = part.slice(separator + 1).trim();
    values.set(key, [...(values.get(key) ?? []), value]);
  }

  const timestamp = Number(values.get("t")?.[0]);
  if (!Number.isSafeInteger(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest();
  return (values.get("v1") ?? []).some((signature) => {
    const received = Buffer.from(signature, "hex");
    return (
      received.length === expected.length &&
      timingSafeEqual(received, expected)
    );
  });
}

Compute the signature over the body exactly as received. If you parse the JSON and turn it back into text first, the bytes change and the signature won't match.

Responses and retries

  • Reply with any 2xx status within 15 seconds to confirm you received the event.
  • Network errors, timeouts, and 408, 409, 425, 429, and 5xx replies are retried. Any other reply, including redirects and other 4xx codes, fails the delivery right away.
  • Hourzero makes up to 10 attempts in total, waiting about 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours, and then a day between tries. It stops retrying three days after the event.
  • The same event can arrive more than once, and events can arrive out of order. Use X-Hourzero-Event-Id to skip duplicates, and created_at to order events.

Troubleshooting

"Webhook endpoint URL is not allowed"

The address must start with https:// and point to a public website. Addresses with a username or password, a # part, or a private or local network address are refused.

Events show "No endpoints"

No active endpoint was subscribed to that event when it happened. Check that the event is ticked in Edit. For test chats, also turn on Include playground events.

Events show "Failed"

Select the eye icon on the event and look at Attempt logs. The HTTP column shows how the other side replied, for example 404 if the address is wrong or 401 if it refused the request. Fix the problem on that side, then select Resend.

My developer says the signature doesn't match

Check that they use the latest secret. After Rotate secret, the old one stops working. Also check that they verify the raw body before parsing it.

Next steps