Skip to main content

Webhook Subscriptions

Webhook subscriptions allow you to receive real-time notifications when specific events occur in your AI Agents. When an event is triggered, Cubeo AI will send an HTTP POST request to your specified URL with the event payload.

Overview

Webhooks enable you to:

  • Receive real-time notifications when events occur
  • Build integrations that react to AI Agent activities
  • Track and log AI Agent interactions
  • Trigger workflows in your own systems

Authentication

All webhook subscription API endpoints require authentication. Include your API key in the request headers:

Authorization: Api-Key YOUR_API_KEY

See the Authentication guide for more details.

Base URL

All webhook subscription endpoints are accessed through:

https://app.cubeo.ai/api/a/{team_slug}/webhook-subscriptions/

Replace {team_slug} with your team's slug.

Available Events

chat_message_created

Triggered whenever a new message is created in a chat conversation. This includes both human messages and AI-generated messages.

Event Name: chat_message_created

When it's triggered:

  • A user sends a message to an AI Agent
  • An AI Agent generates a response
  • A tool execution message is created

run_finished

Triggered when an AI Agent completes processing a user's message and finishes its run cycle.

Event Name: run_finished

When it's triggered:

  • After the AI Agent completes all tool calls and generates a final response

Webhook Subscription Object

A webhook subscription has the following structure:

FieldTypeDescription
idintegerUnique identifier for the webhook subscription (read-only)
eventstringThe event type to subscribe to (chat_message_created or run_finished)
urlstringThe URL where webhook payloads will be sent
statusstringCurrent status: active, inactive, or failed
chatbot_iduuid(Optional) Specific AI Agent ID to filter events. If not provided, events from all AI Assistants in the team will be sent
number_of_consecutive_failuresintegerNumber of consecutive failed delivery attempts (read-only)
last_failure_reasonstringReason for the last delivery failure (read-only)

API Endpoints

Create a Webhook Subscription

Create a new webhook subscription to start receiving event notifications.

Endpoint: POST /api/a/{team_slug}/webhook-subscriptions/

Request Body:

{
"event": "chat_message_created",
"url": "https://your-domain.com/webhooks/chat-message",
"chatbot_id": "123e4567-e89b-12d3-a456-426614174000"
}

Parameters:

  • event (required): The event type (chat_message_created or run_finished)
  • url (required): Your webhook endpoint URL (must be a valid HTTPS URL)
  • chatbot_id (optional): UUID of the specific AI Agent. Omit to receive events from all AI Assistants

Response:

{
"id": 1,
"event": "chat_message_created",
"url": "https://your-domain.com/webhooks/chat-message",
"status": "active",
"chatbot_id": "123e4567-e89b-12d3-a456-426614174000",
"number_of_consecutive_failures": 0,
"last_failure_reason": null
}

List Webhook Subscriptions

Retrieve all webhook subscriptions for your team.

Endpoint: GET /api/a/{team_slug}/webhook-subscriptions/

Response:

[
{
"id": 1,
"event": "chat_message_created",
"url": "https://your-domain.com/webhooks/chat-message",
"status": "active",
"chatbot_id": "123e4567-e89b-12d3-a456-426614174000",
"number_of_consecutive_failures": 0,
"last_failure_reason": null
},
{
"id": 2,
"event": "run_finished",
"url": "https://your-domain.com/webhooks/run-finished",
"status": "active",
"chatbot_id": null,
"number_of_consecutive_failures": 0,
"last_failure_reason": null
}
]

Retrieve a Webhook Subscription

Get details of a specific webhook subscription.

Endpoint: GET /api/a/{team_slug}/webhook-subscriptions/{id}/

Response:

{
"id": 1,
"event": "chat_message_created",
"url": "https://your-domain.com/webhooks/chat-message",
"status": "active",
"chatbot_id": "123e4567-e89b-12d3-a456-426614174000",
"number_of_consecutive_failures": 0,
"last_failure_reason": null
}

Update a Webhook Subscription

Update an existing webhook subscription.

Endpoint: PUT /api/a/{team_slug}/webhook-subscriptions/{id}/

Request Body:

{
"event": "chat_message_created",
"url": "https://your-new-domain.com/webhooks/chat-message",
"status": "active",
"chatbot_id": "123e4567-e89b-12d3-a456-426614174000"
}

Partial Update a Webhook Subscription

Partially update a webhook subscription (only send fields you want to change).

Endpoint: PATCH /api/a/{team_slug}/webhook-subscriptions/{id}/

Request Body:

{
"status": "inactive"
}

Delete a Webhook Subscription

Delete a webhook subscription to stop receiving events.

Endpoint: DELETE /api/a/{team_slug}/webhook-subscriptions/{id}/

Response: 204 No Content

Event Payloads

chat_message_created Payload

When the chat_message_created event is triggered, the following payload is sent to your webhook URL:

{
"chat_id": "123e4567-e89b-12d3-a456-426614174000",
"message": {
"id": 12345,
"chat": "123e4567-e89b-12d3-a456-426614174000",
"message_type": "human",
"content": "What is the weather today?",
"created_at": "2024-01-15T10:30:00.000Z",
"tool_name": null,
"thumbnail_url": null,
"tool_input": null,
"ai_assistant_run_id": "987e6543-e21b-12d3-a456-426614174111",
"llm_model": "GPT-4",
"is_summary": false
},
"ai_assistant_id": "123e4567-e89b-12d3-a456-426614174000",
"metadata": null
}

Payload Fields:

  • chat_id: UUID of the chat conversation
  • message: The message object containing:
    • id: Unique message identifier
    • chat: UUID of the chat this message belongs to
    • message_type: Type of message - human (user message), ai (AI response), tool (tool execution)
    • content: The actual message content/text
    • created_at: Timestamp when the message was created
    • tool_name: Name of the tool if this is a tool message (null otherwise)
    • thumbnail_url: URL to a thumbnail image if applicable
    • tool_input: Input parameters passed to a tool if this is a tool message
    • ai_assistant_run_id: UUID of the AI Agent run that generated this message
    • llm_model: The LLM model used (e.g., "GPT-4", "GPT-3.5-turbo")
    • is_summary: Boolean indicating if this is a conversation summary
  • ai_assistant_id: UUID of the AI Agent that handled this message
  • metadata: Custom metadata (if any)

run_finished Payload

When the run_finished event is triggered, the following payload is sent to your webhook URL:

{
"run_id": "987e6543-e21b-12d3-a456-426614174111",
"chat_id": "123e4567-e89b-12d3-a456-426614174000",
"message": {
"id": 12345,
"chat": "123e4567-e89b-12d3-a456-426614174000",
"message_type": "human",
"content": "What is the weather today?",
"created_at": "2024-01-15T10:30:00.000Z",
"tool_name": null,
"thumbnail_url": null,
"tool_input": null,
"ai_assistant_run_id": "987e6543-e21b-12d3-a456-426614174111",
"llm_model": null,
"is_summary": false
},
"chat_messages": [
{
"id": 12345,
"chat": "123e4567-e89b-12d3-a456-426614174000",
"message_type": "human",
"content": "What is the weather today?",
"created_at": "2024-01-15T10:30:00.000Z",
"tool_name": null,
"thumbnail_url": null,
"tool_input": null,
"ai_assistant_run_id": "987e6543-e21b-12d3-a456-426614174111",
"llm_model": null,
"is_summary": false
},
{
"id": 12346,
"chat": "123e4567-e89b-12d3-a456-426614174000",
"message_type": "ai",
"content": "Today's weather is sunny with a high of 75°F.",
"created_at": "2024-01-15T10:30:05.000Z",
"tool_name": null,
"thumbnail_url": null,
"tool_input": null,
"ai_assistant_run_id": "987e6543-e21b-12d3-a456-426614174111",
"llm_model": "GPT-4",
"is_summary": false
}
],
"last_ai_message": {
"id": 12346,
"chat": "123e4567-e89b-12d3-a456-426614174000",
"message_type": "ai",
"content": "Today's weather is sunny with a high of 75°F.",
"created_at": "2024-01-15T10:30:05.000Z",
"tool_name": null,
"thumbnail_url": null,
"tool_input": null,
"ai_assistant_run_id": "987e6543-e21b-12d3-a456-426614174111",
"llm_model": "GPT-4",
"is_summary": false
},
"last_ai_message_text": "Today's weather is sunny with a high of 75°F.",
"usage_metadata": {
"total_input_tokens": 150,
"total_output_tokens": 45,
"total_cache_read_tokens": 0,
"total_cache_write_tokens": 0,
"total_tool_runs": 1,
"total_consumed_llm_credits": 0.0001234567,
"total_consumed_tools_credits": 0.0000234567,
"total_consumed_cache_read_credits": 0.0,
"total_consumed_cache_write_credits": 0.0,
"total_consumed_credits": 0.0001469134
},
"ai_assistant_id": "123e4567-e89b-12d3-a456-426614174000",
"metadata": null
}

Payload Fields:

  • run_id: UUID of the completed run
  • chat_id: UUID of the chat conversation
  • message: The initial user message that triggered this run
  • chat_messages: Array of all messages generated during this run (visible in history)
  • last_ai_message: The final AI-generated message object
  • last_ai_message_text: The text content of the final AI message (convenient shortcut)
  • usage_metadata: Token usage and credits consumed:
    • total_input_tokens: Total input tokens sent to the LLM
    • total_output_tokens: Total output tokens generated
    • total_cache_read_tokens: Tokens read from cache (discounted cost)
    • total_cache_write_tokens: Tokens written to cache
    • total_tool_runs: Number of tools executed
    • total_consumed_llm_credits: Credits consumed for LLM tokens
    • total_consumed_tools_credits: Credits consumed for tool executions
    • total_consumed_cache_read_credits: Credits consumed for cache reads
    • total_consumed_cache_write_credits: Credits consumed for cache writes
    • total_consumed_credits: Total credits consumed
  • ai_assistant_id: UUID of the AI Agent
  • metadata: Custom metadata associated with the run

Webhook Delivery

HTTP Request

Cubeo AI sends webhook events as HTTP POST requests to your specified URL with the following characteristics:

  • Method: POST
  • Content-Type: application/json
  • Body: JSON payload containing the event data

Response Requirements

Your webhook endpoint should:

  • Respond with HTTP status code 2xx (200-299) to indicate successful receipt
  • Respond within 30 seconds
  • Process the webhook asynchronously if needed

Retry Logic

If your endpoint fails to respond successfully:

  • Cubeo AI will retry the webhook up to 5 times
  • Retry attempts use an exponential backoff strategy (10 seconds initial delay)
  • After 5 consecutive failures, the webhook subscription status will be set to failed
  • You can monitor failures using the number_of_consecutive_failures and last_failure_reason fields

Webhook Logs

You can view the delivery logs for your webhooks.

Endpoint: GET /api/a/{team_slug}/webhook-subscriptions/logs/

Response:

{
"count": 150,
"next": "https://app.cubeo.ai/api/a/your-team/webhook-subscriptions/logs/?page=2",
"previous": null,
"results": [
{
"id": 1001,
"created_at": "2024-01-15T10:30:00.000Z",
"updated_at": "2024-01-15T10:30:02.000Z",
"webhook_subscription": 1,
"payload": {
"chat_id": "123e4567-e89b-12d3-a456-426614174000",
"message": { /* message object */ },
"ai_assistant_id": "123e4567-e89b-12d3-a456-426614174000",
"metadata": null
},
"status": "sent",
"failure_reason": null
}
]
}

Log Status Values:

  • queued: Webhook is queued for delivery
  • in_progress: Webhook is being delivered
  • sent: Webhook was successfully delivered
  • failed: Webhook delivery failed

Security Best Practices

  1. Use HTTPS: Always use HTTPS URLs for your webhook endpoints
  2. Validate Payloads: Verify that incoming requests are from Cubeo AI
  3. Handle Duplicates: Implement idempotency to handle duplicate webhook deliveries
  4. Process Asynchronously: Queue webhook processing to respond quickly
  5. Monitor Failures: Regularly check the number_of_consecutive_failures field

Example Implementation

Node.js / Express

const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhooks/chat-message', async (req, res) => {
try {
const event = req.body;

console.log('Received chat_message_created event');
console.log('Chat ID:', event.chat_id);
console.log('Message:', event.message.content);
console.log('Message Type:', event.message.message_type);

// Process the webhook asynchronously
// await processWebhook(event);

// Respond immediately
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});

Python / Flask

from flask import Flask, request, jsonify
import logging

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

@app.route('/webhooks/chat-message', methods=['POST'])
def handle_chat_message_webhook():
try:
event = request.json

logging.info('Received chat_message_created event')
logging.info(f"Chat ID: {event['chat_id']}")
logging.info(f"Message: {event['message']['content']}")
logging.info(f"Message Type: {event['message']['message_type']}")

# Process the webhook asynchronously
# process_webhook(event)

# Respond immediately
return jsonify({'received': True}), 200

except Exception as e:
logging.error(f'Webhook processing error: {e}')
return jsonify({'error': 'Internal server error'}), 500

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

Python / Django

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
import json
import logging

logger = logging.getLogger(__name__)

@csrf_exempt
@require_http_methods(["POST"])
def handle_chat_message_webhook(request):
try:
event = json.loads(request.body)

logger.info('Received chat_message_created event')
logger.info(f"Chat ID: {event['chat_id']}")
logger.info(f"Message: {event['message']['content']}")
logger.info(f"Message Type: {event['message']['message_type']}")

# Process the webhook asynchronously
# from .tasks import process_webhook_task
# process_webhook_task.delay(event)

# Respond immediately
return JsonResponse({'received': True}, status=200)

except Exception as e:
logger.error(f'Webhook processing error: {e}')
return JsonResponse({'error': 'Internal server error'}, status=500)

Testing Webhooks

You can use services like webhook.site or ngrok to test your webhook integration during development.

Using webhook.site

  1. Go to webhook.site
  2. Copy your unique URL
  3. Create a webhook subscription with that URL
  4. Trigger events in your AI Agent
  5. View the received payloads in real-time on webhook.site

Using ngrok

  1. Install ngrok and start a tunnel to your local server:
    ngrok http 3000
  2. Use the ngrok HTTPS URL in your webhook subscription
  3. Test your local webhook endpoint with real events

Common Use Cases

1. Real-time Chat Monitoring

Monitor all chat messages in real-time for:

  • Content moderation
  • Compliance logging
  • Analytics and reporting
// Subscribe to all messages across all AI Assistants
{
"event": "chat_message_created",
"url": "https://your-domain.com/webhooks/monitor"
}

2. Integration with External Systems

Trigger actions in external systems when AI Agent runs complete:

// Get notified when runs finish to update your CRM
{
"event": "run_finished",
"url": "https://your-domain.com/webhooks/crm-update",
"chatbot_id": "your-Agent-id"
}

3. Usage Tracking and Billing

Track token usage and credits for internal billing:

// Monitor usage_metadata in run_finished events
{
"event": "run_finished",
"url": "https://your-domain.com/webhooks/usage-tracker"
}

Troubleshooting

Webhook Not Receiving Events

  1. Check Status: Ensure webhook status is active
  2. Verify URL: Confirm your webhook URL is accessible from the internet
  3. Check Logs: Review webhook logs for delivery attempts and errors
  4. Test Endpoint: Use curl or Postman to verify your endpoint is working

High Failure Rate

  1. Response Time: Ensure your endpoint responds within 30 seconds
  2. Status Codes: Return 2xx status codes for successful receipt
  3. Error Handling: Add proper error handling to prevent crashes
  4. Rate Limiting: Ensure your endpoint can handle the expected volume

Missing Events

  1. Filter Settings: Check if chatbot_id filter is correctly set
  2. Event Type: Verify you're subscribed to the correct event type
  3. Status: Ensure the subscription status is active, not failed

Rate Limits

Webhook subscriptions have the following limits:

  • Maximum 100 webhook subscriptions per team
  • Maximum 1000 webhook deliveries per minute per team
  • Maximum 30 second timeout for endpoint response