Elaras/

Webhooks

Webhooks let Elaras notify your server when events happen in real time. Use them to sync conversations to your CRM, trigger automations, notify your team in Slack, or update your database when a lead is captured.

How webhooks work

  1. You register a webhook URL in the Elaras dashboard under Developer > Webhooks.
  2. When an event occurs, Elaras sends a POST request to your URL with a JSON payload and a signature header.
  3. Your server verifies the signature and processes the event.
  4. You respond with any 2xx status within 15 seconds.

If your server does not respond with 2xx, Elaras retries the delivery.

Configuring webhooks

Go to Developer > Webhooks in the Elaras dashboard and click Add webhook:

FieldDescription
URLYour publicly reachable HTTPS endpoint
EventsChoose which events trigger this webhook (or select "All events")

Elaras generates a signing secret automatically when you create the webhook. Copy it from the dashboard — it is only shown once. Store it as an environment variable on your server.

Events

message.created

Fired when an AI response is saved to a session.

{
  "event": "message.created",
  "timestamp": "2026-07-24T10:30:00+00:00",
  "data": {
    "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "chatbot_id": 1,
    "message": {
      "id": 42,
      "role": "assistant",
      "content": "We are open Monday to Friday, 9am to 5pm.",
      "credits_used": 3
    }
  }
}

session.started

Fired when a new session sends its first message.

{
  "event": "session.started",
  "timestamp": "2026-07-24T10:29:55+00:00",
  "data": {
    "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "chatbot_id": 1
  }
}

lead.captured

Fired when a user submits their contact details via the lead capture form or the SDK's submitLead() method.

{
  "event": "lead.captured",
  "timestamp": "2026-07-24T10:31:00+00:00",
  "data": {
    "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "chatbot_id": 1,
    "name": "Jordan",
    "email": "[email protected]"
  }
}

human.takeover

Fired when an operator claims a conversation from the inbox.

{
  "event": "human.takeover",
  "timestamp": "2026-07-24T10:32:00+00:00",
  "data": {
    "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "chatbot_id": 1,
    "operator_name": "Alice",
    "taken_over_by": "[email protected]"
  }
}

conversation.flagged

Fired when the AI flags a conversation for review.

{
  "event": "conversation.flagged",
  "timestamp": "2026-07-24T10:33:00+00:00",
  "data": {
    "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "chatbot_id": 1,
    "flag_id": 7,
    "category": "off_topic",
    "severity": "medium",
    "reason": "User is asking for legal advice outside the agent's scope."
  }
}

Payload structure

Every webhook payload shares this top-level shape:

FieldTypeDescription
eventstringEvent type
timestampstringISO 8601 timestamp of when the event was dispatched
dataobjectEvent-specific data

Elaras also enriches data with session context where available:

FieldDescription
session_urlLink to the conversation in the Elaras dashboard
lead_nameVisitor's name if captured
lead_emailVisitor's email if captured
first_user_messageFirst message the visitor sent (up to 200 chars)
last_user_messageMost recent message the visitor sent (up to 200 chars)

Signature verification

Elaras signs every webhook request with HMAC-SHA256 using the webhook secret. The signature is in the X-Elaras-Signature header:

X-Elaras-Signature: sha256=a1b2c3d4e5f6...

A second header, X-Elaras-Event, contains the event name as a convenience for routing.

Always verify the signature before processing a webhook. This prevents malicious third parties from sending fake events to your endpoint.

Node.js

import crypto from 'crypto';
import express from 'express';

const app = express();

app.post('/webhooks/elaras', express.raw({type: 'application/json'}), (req, res) => {
  const signature     = req.headers['x-elaras-signature'];
  const webhookSecret = process.env.ELARAS_WEBHOOK_SECRET;

  const expected = 'sha256=' + crypto
    .createHmac('sha256', webhookSecret)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  const payload = JSON.parse(req.body);

  switch (payload.event) {
    case 'message.created':
      console.log('New message:', payload.data.message.content);
      break;

    case 'session.started':
      console.log('New session:', payload.data.session_id);
      break;

    case 'lead.captured':
      console.log('Lead:', payload.data.email);
      // e.g. add to your CRM
      break;
  }

  res.status(200).send('ok');
});

PHP

<?php

$rawBody       = file_get_contents('php://input');
$signature     = $_SERVER['HTTP_X_ELARAS_SIGNATURE'] ?? '';
$webhookSecret = getenv('ELARAS_WEBHOOK_SECRET');

$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $webhookSecret);

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

$payload = json_decode($rawBody, true);

switch ($payload['event']) {
    case 'message.created':
        error_log('New message: ' . $payload['data']['message']['content']);
        break;

    case 'session.started':
        error_log('New session: ' . $payload['data']['session_id']);
        break;

    case 'lead.captured':
        error_log('Lead: ' . $payload['data']['email']);
        // Add to your CRM...
        break;
}

http_response_code(200);
echo 'ok';

Retry behaviour

If your endpoint does not return a 2xx response (or times out after 15 seconds), Elaras automatically retries:

AttemptDelay after previous attempt
1st retry1 minute
2nd retry5 minutes

After 3 total attempts (1 initial + 2 retries), the delivery is marked as failed and no further attempts are made.

Responding

  • Respond with any 2xx status code (200, 204, etc.) to acknowledge receipt.
  • Respond within 15 seconds — process the event asynchronously if needed (queue it, then respond 200 immediately).
  • The response body is ignored by Elaras.

Security tips

  • Store your webhook secret in an environment variable — never hardcode it.
  • Use hash_equals() / timingSafeEqual() for comparison — never === or ==. This prevents timing attacks.
  • Only accept HTTPS endpoints.
  • Use a dedicated endpoint for Elaras webhooks rather than a shared route.