Skip to main content

Quick Setup

1

Open webhook settings

Go to Developer → Webhooks and enable the webhook toggle.Webhook Configuration
2

Enter endpoint URL

Must be HTTPS.
3

Select events

Choose room.join, chat.push, or both.
4

Add authentication (optional)

Authorization: Bearer your-api-token
X-API-Key: your-secret-key

Payload Format

All payloads follow the same structure:
FieldTypeDescription
agent_idstringThe agent that triggered the event
event_typestringEvent name (room.join or chat.push)
dataobjectEvent-specific data
timestampfloatUnix timestamp

room.join

{
  "agent_id": "agent_abc123",
  "event_type": "room.join",
  "data": {
    "room_name": "customer-support",
    "participant_count": 1,
    "session_id": "session_xyz789"
  },
  "timestamp": 1705312200.0
}

chat.push

{
  "agent_id": "agent_abc123",
  "event_type": "chat.push",
  "data": {
    "role": "user",
    "message": "Hello, I need help with my order",
    "session_id": "session_xyz789",
    "timestamp": 1705312285.0
  },
  "timestamp": 1705312285.0
}

Implementation Examples

from flask import Flask, request, jsonify
import hmac, hashlib

app = Flask(__name__)
WEBHOOK_SECRET = "your-webhook-secret"

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-bitHuman-Signature', '')
    if not verify_signature(request.data, signature):
        return jsonify({'error': 'Invalid signature'}), 401

    data = request.json
    event_type = data.get('event_type')

    if event_type == 'room.join':
        print(f"User joined session {data['data']['session_id']}")
    elif event_type == 'chat.push':
        print(f"[{data['data']['role']}] {data['data']['message']}")

    return jsonify({'status': 'ok'})

def verify_signature(payload, signature):
    expected = hmac.new(
        WEBHOOK_SECRET.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

if __name__ == '__main__':
    app.run(port=3000)

Signature Verification

All webhook requests include an X-bitHuman-Signature header. Verify it using HMAC SHA-256:
  1. Compute HMAC-SHA256(secret, raw_request_body)
  2. Compare the hex digest against the signature header (strip sha256= prefix)
  3. Use constant-time comparison to prevent timing attacks
Always use HTTPS. HTTP endpoints are rejected.

Testing

Local development with ngrok

ngrok http 3000
# Use the resulting HTTPS URL as your webhook endpoint

Manual curl test

curl -X POST https://your-app.com/webhook \
  -H "Content-Type: application/json" \
  -H "X-bitHuman-Signature: sha256=test" \
  -d '{
    "agent_id": "test_agent",
    "event_type": "room.join",
    "data": {
      "room_name": "test-room",
      "participant_count": 1,
      "session_id": "session_123"
    },
    "timestamp": 1705312200.0
  }'

Retry Policy

Failed deliveries (non-2xx responses) are retried automatically:
AttemptDelay
1st retry1 second
2nd retry5 seconds
3rd retry30 seconds
Maximum 3 retries. Your endpoint must respond within 30 seconds.

Troubleshooting

IssueSolution
Signature invalidVerify HMAC SHA-256 against raw request body
Timeout errorsReturn 200 immediately, process async
404 Not FoundCheck endpoint URL in Developer → Webhooks
SSL errorsUse a valid HTTPS certificate