Webhooks
Webhooks allow external systems to receive notifications when events occur in oHallo. This page covers the current state of webhook support and recommended patterns for real-time data access.
Current status
Section titled “Current status”oHallo’s webhook system is under active development. The platform uses internal event streaming (Kafka) to propagate events between services, but external webhook delivery is not yet generally available.
Internal events
Section titled “Internal events”The following events flow through the platform internally:
| Event | Description |
|---|---|
channel.message_received | A new message arrived on a channel |
conversation.updated | A conversation’s status, summary, or message count changed |
These events power the real-time dashboard updates via WebSocket/SSE but are not yet exposed as external webhooks.
Account provisioning webhook
Section titled “Account provisioning webhook”One webhook is currently active for platform operations:
Kinde organization.created — When a new organisation is created in Kinde (the authentication provider), oHallo automatically provisions an account, creates a default brand and workspace, and sets up system MCP connections. This is an internal platform webhook and is not configurable.
Planned webhook events
Section titled “Planned webhook events”The following webhook events are planned for a future release:
| Event | Trigger | Payload |
|---|---|---|
conversation.created | A new conversation is started (inbound or outbound) | Conversation ID, channel, contact, workspace |
conversation.resolved | A conversation is marked as resolved | Conversation ID, outcome, resolution method (AI or human) |
conversation.status_changed | A conversation transitions between statuses | Conversation ID, old status, new status |
message.received | A new inbound message is received | Message ID, conversation ID, sender, body preview |
message.sent | An outbound message is delivered | Message ID, conversation ID, delivery status |
attention_item.created | An attention item is raised | Attention item ID, type, conversation ID |
kb_entry.proposed | The learning loop proposes a new KB entry | Entry ID, question, answer, confidence |
policy_entry.proposed | The learning loop proposes a new policy entry | Entry ID, topic, rule text, confidence |
When available, webhooks will use the following delivery model:
- HTTPS POST to your registered endpoint
- JSON payload with event type and data
- HMAC-SHA256 signature in the
X-OHallo-Signatureheader for verification - Retry with exponential backoff on 4xx/5xx responses (up to 3 attempts)
- Idempotency key in the payload to handle duplicate deliveries
Recommended approach: polling
Section titled “Recommended approach: polling”Until external webhooks are available, use the REST API to poll for changes. Here is a practical pattern:
Poll for new or updated conversations
Section titled “Poll for new or updated conversations”const API_BASE = "https://api.ohallo.eu";const API_KEY = "sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx";const WORKSPACE_ID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
let lastChecked = new Date().toISOString();
async function pollConversations(): Promise<void> { const response = await fetch( `${API_BASE}/api/conversations?workspaceId=${WORKSPACE_ID}&updatedSince=${lastChecked}`, { headers: { "Authorization": `Bearer ${API_KEY}`, }, } );
if (!response.ok) { console.error(`Poll failed: ${response.status}`); return; }
const data = await response.json();
for (const conversation of data.items) { // Process each updated conversation console.log(`Conversation ${conversation.id}: ${conversation.status}`); }
lastChecked = new Date().toISOString();}
// Poll every 30 secondssetInterval(pollConversations, 30_000);Poll for pending KB entries
Section titled “Poll for pending KB entries”async function pollPendingKBEntries(): Promise<void> { const response = await fetch( `${API_BASE}/api/workspaces/${WORKSPACE_ID}/kb-entries/pending`, { headers: { "Authorization": `Bearer ${API_KEY}`, }, } );
if (!response.ok) return;
const data = await response.json();
for (const entry of data.items) { // Review and auto-approve entries with high confidence if (entry.confidence && entry.confidence >= 0.9) { await fetch(`${API_BASE}/api/kb-entries/${entry.id}/approve`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, }, }); console.log(`Auto-approved KB entry: ${entry.question}`); } }}
// Poll every 5 minutessetInterval(pollPendingKBEntries, 300_000);Polling guidelines
Section titled “Polling guidelines”- Conversations: Poll every 15—30 seconds for near-real-time updates. Use the
updatedSinceparameter to fetch only changed records. - KB and policy entries: Poll every 5—15 minutes. Pending entries do not require immediate action.
- Attention items: Poll every 1—5 minutes depending on urgency requirements.
- Rate limits: With a limit of 300 requests per minute, you can comfortably poll multiple endpoints at reasonable intervals. A typical integration polling conversations (every 30s), KB entries (every 5min), and attention items (every 2min) uses approximately 3 requests per minute.
Stay informed
Section titled “Stay informed”Webhook support will be announced in the changelog. If you have specific requirements for event delivery, contact the oHallo team to discuss your use case.