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:
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier for the webhook subscription (read-only) |
event | string | The event type to subscribe to (chat_message_created or run_finished) |
url | string | The URL where webhook payloads will be sent |
status | string | Current status: active, inactive, or failed |
chatbot_id | uuid | (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_failures | integer | Number of consecutive failed delivery attempts (read-only) |
last_failure_reason | string | Reason 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_createdorrun_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 conversationmessage: The message object containing:id: Unique message identifierchat: UUID of the chat this message belongs tomessage_type: Type of message -human(user message),ai(AI response),tool(tool execution)content: The actual message content/textcreated_at: Timestamp when the message was createdtool_name: Name of the tool if this is a tool message (null otherwise)thumbnail_url: URL to a thumbnail image if applicabletool_input: Input parameters passed to a tool if this is a tool messageai_assistant_run_id: UUID of the AI Agent run that generated this messagellm_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 messagemetadata: 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 runchat_id: UUID of the chat conversationmessage: The initial user message that triggered this runchat_messages: Array of all messages generated during this run (visible in history)last_ai_message: The final AI-generated message objectlast_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 LLMtotal_output_tokens: Total output tokens generatedtotal_cache_read_tokens: Tokens read from cache (discounted cost)total_cache_write_tokens: Tokens written to cachetotal_tool_runs: Number of tools executedtotal_consumed_llm_credits: Credits consumed for LLM tokenstotal_consumed_tools_credits: Credits consumed for tool executionstotal_consumed_cache_read_credits: Credits consumed for cache readstotal_consumed_cache_write_credits: Credits consumed for cache writestotal_consumed_credits: Total credits consumed
ai_assistant_id: UUID of the AI Agentmetadata: 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_failuresandlast_failure_reasonfields
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 deliveryin_progress: Webhook is being deliveredsent: Webhook was successfully deliveredfailed: Webhook delivery failed
Security Best Practices
- Use HTTPS: Always use HTTPS URLs for your webhook endpoints
- Validate Payloads: Verify that incoming requests are from Cubeo AI
- Handle Duplicates: Implement idempotency to handle duplicate webhook deliveries
- Process Asynchronously: Queue webhook processing to respond quickly
- Monitor Failures: Regularly check the
number_of_consecutive_failuresfield
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
- Go to webhook.site
- Copy your unique URL
- Create a webhook subscription with that URL
- Trigger events in your AI Agent
- View the received payloads in real-time on webhook.site
Using ngrok
- Install ngrok and start a tunnel to your local server:
ngrok http 3000 - Use the ngrok HTTPS URL in your webhook subscription
- 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
- Check Status: Ensure webhook status is
active - Verify URL: Confirm your webhook URL is accessible from the internet
- Check Logs: Review webhook logs for delivery attempts and errors
- Test Endpoint: Use curl or Postman to verify your endpoint is working
High Failure Rate
- Response Time: Ensure your endpoint responds within 30 seconds
- Status Codes: Return 2xx status codes for successful receipt
- Error Handling: Add proper error handling to prevent crashes
- Rate Limiting: Ensure your endpoint can handle the expected volume
Missing Events
- Filter Settings: Check if
chatbot_idfilter is correctly set - Event Type: Verify you're subscribed to the correct event type
- Status: Ensure the subscription status is
active, notfailed
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