1. Developers
  2. Webhooks

Webhooks

Get a signed POST on your server the moment something changes in a HowdyBell workspace.

Updated October 5, 2026

A webhook endpoint is a URL on your server. When an event you picked happens, HowdyBell sends it a JSON POST. Endpoints are added by a workspace owner or manager in the app, and every delivery is signed so you can prove it came from HowdyBell.

Add an endpoint

  1. In HowdyBell, open Settings, then Integrations.
  2. In the API keys and webhooks card, under Webhooks, enter your Endpoint URL.
  3. Keep All events ticked, or untick it and pick the events you want.
  4. Click Add endpoint.
  5. Copy the signing secret shown once. You need it to check signatures.

Use Send test to queue a ping event to the endpoint.

The URL must be a public https address. Private and internal addresses are refused, and redirects are not followed.

What a delivery looks like

POST /hooks/howdybell HTTP/1.1
Content-Type: application/json
X-HowdyBell-Event: contact.created
X-HowdyBell-Delivery: 8812
X-HowdyBell-Signature: t=1791230400,v1=5f2a...c9
{
  "id": 8812,
  "event": "contact.created",
  "created_at": "2026-10-05T14:30:00Z",
  "data": { "...": "the record that changed" }
}

The shape of data depends on the event. Call Get sample payloads with an event name to see real examples from your workspace.

Check the signature

X-HowdyBell-Signature holds a Unix timestamp t and v1, the hex HMAC SHA-256 of "{t}.{raw body}" keyed with your signing secret. Compute it over the raw bytes you received, before any JSON parsing.

const crypto = require("crypto");

function isFromHowdyBell(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 || "");
  // Reject old timestamps too, so a captured request cannot be replayed later.
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && a.length === b.length && crypto.timingSafeEqual(a, b);
}

Retries

Answer with any 2xx status within 10 seconds. Anything else, a timeout or a redirect counts as a failed attempt. HowdyBell tries each delivery up to 5 times, waiting 1, 5, 30 and then 120 minutes between attempts. After the fifth failure the delivery is marked failed.

Deliveries can arrive more than once and out of order. Use X-HowdyBell-Delivery to skip duplicates.

Events

ping, location.created, location.updated, user.invited, contact.created, contact.updated, contact.deleted, opportunity.created, opportunity.stage_changed, task.created, task.completed, note.added, conversation.created, conversation.updated, message.received, message.sent, message.failed, workflow.run_started, workflow.run_finished, page.viewed, form.submitted, survey.submitted, quiz.submitted, trigger_link.clicked, review.received, review.replied, review_request.sent, review_request.clicked, video_testimonial.received, social_post.published, social_post.failed, social_post.approved, invoice.paid, payment.failed, contact.tag_added, contact.tag_removed, appointment.booked, appointment.cancelled.

ping is only sent by Send test.

Webhooks | HowdyBell Developers