helpr docs

Webhooks

Receive real-time HTTP callbacks when events happen in your Helpr workspace — new conversations, messages, and more.

Overview

Webhooks let you subscribe to events in your Helpr workspace. When an event occurs — a visitor starts a conversation, sends a message, or an agent replies — Helpr sends a POST request to your endpoint with the event data.

Use webhooks to sync conversations to your CRM, trigger notifications in Slack, log messages to your data warehouse, or build custom integrations.

Setup

  1. Go to Settings → Developer in the Helpr dashboard
  2. Scroll to the Webhooks section
  3. Click Add Webhook
  4. Enter your HTTPS endpoint URL
  5. Select the events you want to receive
  6. Click Create — copy and save the signing secret immediately

Your endpoint must use HTTPS and respond with a 2xx status code within 10 seconds.

Important: The signing secret is only shown once when you create the webhook. You’ll need it to verify signatures on incoming requests.

Managing Webhooks

All webhook management is done in the Helpr dashboard under Settings → Developer → Webhooks:

  • Pause / Resume — temporarily stop deliveries without deleting the webhook
  • Edit — change the endpoint URL or subscribed events
  • Delete — permanently remove the webhook and its delivery history

If a webhook accumulates 100 consecutive delivery failures, it is automatically disabled. You can re-enable it from the dashboard after fixing your endpoint.

chat.created

Fired when a visitor starts a new conversation (first message in a chat).

{
  "event": "chat.created",
  "timestamp": "2026-04-27T14:32:10+00:00",
  "data": {
    "chat_id": 4521,
    "team_id": 3,
    "visitor_id": "v_8f3a2b1c",
    "identity": {
      "email": "[email protected]",
      "name": "Jane Smith",
      "userId": "usr_123",
      "company": "Acme Inc"
    }
  }
}

The identity object is included when the visitor has been identified via helpr.identify(). It contains whichever fields were set: email, name, userId, company, phone. If the visitor is anonymous, the identity field is omitted.

chat.message

Fired on every public message in a conversation — from visitors, agents, or bots.

{
  "event": "chat.message",
  "timestamp": "2026-04-27T14:32:10+00:00",
  "data": {
    "chat_id": 4521,
    "message_id": 18923,
    "sender_type": "visitor",
    "sender_name": "Jane Smith",
    "body": "Hi, I need help with my order",
    "identity": {
      "email": "[email protected]",
      "name": "Jane Smith",
      "userId": "usr_123"
    }
  }
}
FieldDescription
chat_idThe conversation ID
message_idUnique message ID
sender_typevisitor, agent, or bot
sender_nameDisplay name of the sender
bodyMessage text content
identityVisitor identity object (omitted if anonymous). See chat.created for available fields

Wildcard Subscription

Pass ["*"] as the events array to receive every event type, including any added in the future.

{
  "url": "https://your-server.com/helpr/webhook",
  "events": ["*"]
}

Request Format

Every webhook delivery is an HTTP POST with a JSON body and these headers:

HeaderExampleDescription
Content-Typeapplication/jsonAlways JSON
X-Helpr-Signaturesha256=a1b2c3d4...HMAC-SHA256 signature of the request body
X-Helpr-Eventchat.messageThe event type
X-Helpr-Delivery98231Unique delivery ID (useful for deduplication)

Signature Verification

Every request is signed with your webhook’s secret using HMAC-SHA256. Always verify signatures before processing the payload.

const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your request handler:
app.post('/helpr/webhook', (req, res) => {
  const sig = req.headers['x-helpr-signature']?.replace('sha256=', '');
  if (!sig || !verifySignature(req.rawBody, sig, process.env.HELPR_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const { event, data } = JSON.parse(req.rawBody);

  switch (event) {
    case 'chat.created':
      console.log('New chat:', data.chat_id);
      break;
    case 'chat.message':
      console.log(`${data.sender_name}: ${data.body}`);
      break;
  }

  res.status(200).send('ok');
});
import hmac, hashlib, os

def verify(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# In your handler:
sig = request.headers.get('X-Helpr-Signature', '').removeprefix('sha256=')
if not verify(request.data, sig, os.environ['HELPR_WEBHOOK_SECRET']):
    return 'Invalid signature', 401

data = request.json
print(f"Event: {data['event']}, Data: {data['data']}")
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_HELPR_SIGNATURE'] ?? '';
$secret    = getenv('HELPR_WEBHOOK_SECRET');

$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = $_SERVER['HTTP_X_HELPR_EVENT'] ?? '';
$data  = json_decode($payload, true);

// Handle the event...
switch ($data['event']) {
    case 'chat.created':
        // New conversation started
        break;
    case 'chat.message':
        // New message received
        break;
}

Retries & Failures

Helpr expects a 2xx response within 10 seconds. If your endpoint fails or times out, delivery is retried with exponential backoff:

AttemptRetry after
1st failure10 seconds
2nd failure60 seconds
3rd failure5 minutes
4th failureMarked as failed

After 100 consecutive failures across all deliveries, the webhook is automatically disabled. A single successful delivery resets the failure counter to zero.

To re-enable a disabled webhook, update its status to active.

Best Practices

  • Return 200 quickly. Process events asynchronously — queue the payload, respond immediately. If your handler takes more than 10 seconds, the delivery is marked as failed.
  • Deduplicate with the delivery ID. The same event may be delivered more than once during retries. Use the X-Helpr-Delivery header to detect duplicates.
  • Always verify signatures. Validate X-Helpr-Signature before trusting the payload. Use constant-time comparison to prevent timing attacks.
  • Use HTTPS. Webhook payloads contain conversation data. Only HTTPS endpoints are accepted.
  • Monitor your endpoint. If your endpoint starts failing, Helpr disables the webhook after 100 consecutive failures. Set up alerting on your side.