Skip to content

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.

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.

The following events flow through the platform internally:

EventDescription
channel.message_receivedA new message arrived on a channel
conversation.updatedA 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.

One webhook is currently active for platform operations:

organization.created: When a new organisation is created in 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.

The following webhook events are planned for a future release:

EventTriggerPayload
conversation.createdA new conversation is started (inbound or outbound)Conversation ID, channel, contact, workspace
conversation.resolvedA conversation is marked as resolvedConversation ID, outcome, resolution method (assistant or human)
conversation.status_changedA conversation transitions between statusesConversation ID, old status, new status
message.receivedA new inbound message is receivedMessage ID, conversation ID, sender, body preview
message.sentAn outbound message is deliveredMessage ID, conversation ID, delivery status
attention_item.createdAn attention item is raisedAttention item ID, type, conversation ID
kb_entry.proposedThe learning loop proposes a new KB entryEntry ID, question, answer, confidence
policy_entry.proposedThe learning loop proposes a new policy entryEntry 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-Signature header for verification
  • Retry with exponential backoff on 4xx/5xx responses (up to 3 attempts)
  • Idempotency key in the payload to handle duplicate deliveries

Until external webhooks are available, use the REST API to poll for changes. Here is a practical pattern:

GET /api/conversations is cursor-paginated: the response is { "data": [...], "nextCursor": "..." }, and nextCursor is omitted once you reach the end. Track the newest conversation you have already seen so you only act on genuinely new activity. To page through a large result set, pass the cursor value back on the next call.

const API_BASE = "https://api.ohallo.eu";
const API_KEY = "sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx";
const WORKSPACE_ID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
const seen = new Set<string>();
async function pollConversations(): Promise<void> {
const response = await fetch(
`${API_BASE}/api/conversations?workspaceId=${WORKSPACE_ID}&limit=50`,
{
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.data) {
if (seen.has(conversation.id)) continue;
seen.add(conversation.id);
// Process each new or updated conversation
console.log(`Conversation ${conversation.id}: ${conversation.status}`);
}
// `data.nextCursor` is present only when more pages remain. Pass it back as
// `&cursor=<value>` to continue paging; omit it to start from the top again.
}
// Poll every 30 seconds
setInterval(pollConversations, 30_000);
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;
// The pending endpoint returns a bare JSON array of entries.
const entries = await response.json();
for (const entry of entries) {
// 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 minutes
setInterval(pollPendingKBEntries, 300_000);
  • Conversations: Poll every 15 to 30 seconds for near-real-time updates. The list is ordered by recent activity, so the first page surfaces the latest changes; track ids you have already processed to avoid acting on the same conversation twice.
  • KB and policy entries: Poll every 5 to 15 minutes. Pending entries do not require immediate action.
  • Attention items: Poll every 1 to 5 minutes depending on urgency requirements.
  • Rate limits: The API allows 600 requests per minute per client IP in production. A typical integration polling conversations (every 30s), KB entries (every 5min), and attention items (every 2min) uses only a few requests per minute, well within budget.

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.