Conversations
Conversations are the core resource in oHallo. Each conversation represents a message thread between a customer contact and oHallo on a single channel.
Required scope: conversations:read for GET endpoints, conversations:write for POST endpoints.
List conversations
Section titled “List conversations”Retrieve conversations for a workspace, optionally filtered by status or contact.
curl "https://api.ohallo.eu/api/conversations?workspaceId=a1b2c3d4-e5f6-7890-abcd-ef1234567890&status=open&limit=50" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
workspaceId | UUID | No | Filter by workspace |
status | string | No | Filter by status: open, in_progress, awaiting_contact, resolved, closed, abandoned |
contactId | UUID | No | Filter by contact |
accountId | UUID | No | Filter by account |
q | string | No | Free-text search across contact name / email / subject |
humanManaged | boolean | No | Filter to conversations currently owned by a human operator |
assignee | string | No | Filter to conversations assigned to a specific user id, or me for the calling user (resolved server-side; meaningful for dashboard sessions, where API-key callers should pass an explicit user id) |
hasAttention | boolean | No | Filter to conversations with one or more open attention items |
limit | integer | No | Page size (default 50, max 100) |
cursor | string | No | Opaque pagination cursor from a previous response’s nextCursor |
Response:
{ "data": [ { "id": "c9f8e7d6-b5a4-3210-fedc-ba9876543210", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "channelId": "d4e5f6a7-b8c9-0123-4567-890abcdef012", "contactId": "f7e8d9c0-b1a2-3456-7890-abcdef123456", "status": "open", "lastMessagePreview": "Hi, I placed order NP-2026-0142 last week. Can you tell me when...", "lastMessageAt": "2026-03-15T14:30:00.000Z", "contactName": "Henrik Larsen", "contactEmail": "henrik@nordic-parts.dk", "accountName": "Nordic Parts ApS" } ], "nextCursor": "eyJsYXN0SWQiOiJjOWY4ZTdkNi1iNWE0LTMyMTAtZmVkYy1iYTk4NzY1NDMyMTAifQ=="}Pagination is cursor-based: pass the nextCursor value from one response as the cursor query param of the next. When the response omits nextCursor, there are no more items. Optional fields (contactName, contactEmail, accountName, humanManaged, formType, autoResolved, lastTurnRoutingPath) are only included on conversations that have those signals. Do not rely on their presence in every item.
Get conversation
Section titled “Get conversation”Retrieve full details for a single conversation: the conversation row, the resolved contact + account records, the message history, the per-turn context entries, and any attention items raised by the agent pipeline.
curl "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Response:
{ "id": "c9f8e7d6-b5a4-3210-fedc-ba9876543210", "tenantId": "10000000-0000-4000-8000-000000000001", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "channelId": "d4e5f6a7-b8c9-0123-4567-890abcdef012", "channelType": "email", "contactId": "f7e8d9c0-b1a2-3456-7890-abcdef123456", "accountId": "33445566-7788-99aa-bbcc-ddeeff001122", "status": "in_progress", "stateSummary": "Customer inquired about delivery date for order NP-2026-0142...", "outcome": null, "humanManagingUserId": null, "lastActivityAt": "2026-03-15T14:35:00.000Z", "createdAt": "2026-03-15T09:12:00.000Z", "updatedAt": "2026-03-15T14:35:00.000Z", "contact": { "id": "f7e8d9c0-...", "firstName": "Henrik", "lastName": "Larsen", "email": "henrik@nordic-parts.dk" }, "account": { "id": "33445566-...", "name": "Nordic Parts ApS" }, "history": [ /* array of message objects — see Get messages below */ ], "contextEntries": [ /* KB + policy entries the assistant used on the latest turn */ ], "attentionItems": [ /* attention items raised for this conversation */ ]}The contact, account, history, contextEntries, and attentionItems fields are only present when the corresponding upstream fetch succeeds. There is no subject or messageCount field. stateSummary holds the platform-maintained running summary, and the history array length gives you the count.
Get messages
Section titled “Get messages”Retrieve the message history for a conversation, ordered chronologically.
curl "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/messages" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Response: returns a bare array of message objects, ordered chronologically.
[ { "id": "11111111-2222-3333-4444-555555555555", "direction": "inbound", "speaker": null, "body": "Hi, I placed order NP-2026-0142 last week. Can you tell me when it will be delivered?", "sentAt": "2026-03-15T09:12:01.000Z", "channel": "email", "fromAddress": "henrik@nordic-parts.dk", "subject": "Question about order #NP-2026-0142" }, { "id": "66666666-7777-8888-9999-aaaaaaaaaaaa", "direction": "outbound", "speaker": null, "body": "Hello Henrik,\n\nThank you for reaching out...", "sentAt": "2026-03-15T09:12:45.000Z", "channel": "email" }]fromAddress and subject are present when the source channel carries them (typically email). On voice channels, every message has direction: "inbound" but speaker is set to "caller" or "ai" so consumers can render call transcripts correctly.
Get attachments
Section titled “Get attachments”Retrieve attachments for a conversation.
curl "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/attachments" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Response: returns a bare array of attachment objects.
[ { "id": "aaaabbbb-cccc-dddd-eeee-ffffffffffff", "messageId": "11111111-2222-3333-4444-555555555555", "fileName": "purchase-order.pdf", "mimeType": "application/pdf", "sizeBytes": 245780, "status": "ready", "createdAt": "2026-03-15T09:12:01.000Z" }]Reply to conversation
Section titled “Reply to conversation”Send a human-authored reply. This signals the conversation workflow to deliver the message via the original channel.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/reply" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx" \ -H "Content-Type: application/json" \ -d '{ "content": "Henrik, I have just confirmed with our warehouse -- your order shipped this morning. Tracking number: DHL-98765432. You should receive it by end of day tomorrow." }'Response:
{ "ok": true}Resolve conversation
Section titled “Resolve conversation”Mark a conversation as resolved, optionally with an outcome description.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/resolve" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx" \ -H "Content-Type: application/json" \ -d '{ "outcome": "Delivery date confirmed, customer satisfied" }'Response:
{ "ok": true}Take over conversation
Section titled “Take over conversation”Pause the agent pipeline and take manual control of the conversation. While taken over, the platform will not process new messages or send automatic replies.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/take-over" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Release conversation
Section titled “Release conversation”Release a taken-over conversation back to the agent pipeline. The platform resumes processing on the next inbound message.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/release" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Compose outbound conversation
Section titled “Compose outbound conversation”Start a new outbound conversation. This creates a conversation, resolves or creates the contact, and delivers the first message.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/compose" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "channelId": "d4e5f6a7-b8c9-0123-4567-890abcdef012", "contactEmail": "anna@scandinavian-imports.se", "contactName": "Anna Johansson", "content": "Hello Anna,\n\nFollowing up on our conversation about the Q2 catalogue. The new product line is now available. Would you like me to send over the updated pricing?" }'Response:
{ "conversationId": "new_conv_id-1234-5678-9abc-def012345678"}Attention items
Section titled “Attention items”Attention items are flags raised by the agent pipeline when something requires human review, for example an MCP tool failure, a discrepancy between KB entries, or a validation failure.
List attention items
Section titled “List attention items”curl "https://api.ohallo.eu/api/attention-items?workspaceId=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
workspaceId | UUID | No | Filter to a single workspace |
status | string | No | open, acknowledged, resolved, or dismissed (default returns all) |
conversationId | UUID | No | Filter to a single conversation |
Response: returns a bare array of attention items.
[ { "id": "11112222-3333-4444-5555-666677778888", "tenantId": "10000000-0000-4000-8000-000000000001", "conversationId": "c9f8e7d6-b5a4-3210-fedc-ba9876543210", "type": "mcp_failure", "status": "open", "context": { "toolName": "get_order", "error": "Connection timeout after 30s" }, "createdAt": "2026-03-15T14:30:00.000Z", "resolvedAt": null, "turnId": "98765432-1234-5678-90ab-cdef12345678", "assignedToUserId": null }]type is one of: validation_failed, approval_gate, escalation, mcp_failure, auth_failure, customer_reply_pending, expiry_warning. The context JSON object varies by type.
Resolve attention item
Section titled “Resolve attention item”curl -X POST "https://api.ohallo.eu/api/attention-items/11112222-3333-4444-5555-666677778888/resolve" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx" \ -H "Content-Type: application/json" \ -d '{ "reason": "Order delivered, customer confirmed receipt." }'Response: { "ok": true } on success, 404 if the attention item does not belong to your account.
Assign conversation
Section titled “Assign conversation”Assign a conversation to a specific user. userId is the assignee’s identity-provider user id (the userId returned by the users API), not a database uuid. The conversation must already be paused (taken over); assigning a platform-managed conversation returns 409 with { "error": "must_pause_first" }. If the conversation is already assigned to another user, the call returns 409 with { "error": "already_assigned", "currentAssigneeId": "..." } unless overrideExistingAssignment is set to true.
The assignee must be an active workspace user with the agent, admin, or owner role; otherwise the call returns 422 with { "error": "invalid_assignee" }. When called with a dashboard session, callers with the observer or billing role receive 403.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/assign" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx" \ -H "Content-Type: application/json" \ -d '{ "userId": "kp_0123456789abcdef0123456789abcdef", "overrideExistingAssignment": false }'Response: { "ok": true }. Open attention items on the conversation are retargeted to the new assignee.
Unassign conversation
Section titled “Unassign conversation”Remove the assignment, returning the conversation to the shared queue. The pause state is unchanged. Idempotent: unassigning an unassigned conversation returns 200. Dashboard callers with the observer or billing role receive 403.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/unassign" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Approve pending action
Section titled “Approve pending action”Approve a guardrail-gated tool call waiting for human approval. Resumes the agent pipeline.
Required scope: conversations:write
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/approve" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Status counts
Section titled “Status counts”Get aggregate conversation counts by status for a workspace.
Required scope: conversations:read
curl "https://api.ohallo.eu/api/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/conversations/status-counts" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Response:
{ "open": 12, "in_progress": 8, "awaiting_contact": 23, "resolved": 156, "closed": 4, "abandoned": 2}Conversation audit report
Section titled “Conversation audit report”Retrieve a deep audit report for a single conversation. This is the complete record of how the conversation was handled: the contact and account, every message, every turn (orchestrator decisions, specialist executions, tool calls with their policy decisions, and the composed reply with its validation), attention items, identity events, and the workflow activity trace.
Required scope: conversations:read
curl "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/audit" \ -H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"Response (abridged):
{ "meta": { "conversationId": "c9f8e7d6-b5a4-3210-fedc-ba9876543210", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "channelId": "11223344-5566-4788-99aa-bbccddeeff00", "generatedAt": "2026-05-13T10:20:00.000Z", "turnCount": 3, "messageCount": 6, "executionCount": 9 }, "contact": { "contactId": "44556677-8899-4a1b-8c2d-3e4f5a6b7c8d", "firstName": "Jane", "companyName": "Nordic Parts ApS", "identities": [{ "channel": "email", "value": "jane@nordicparts.example" }] }, "account": { "accountId": "...", "name": "Nordic Parts ApS", "country": "DK", "enrichmentStatus": "enriched" }, "conversation": { "status": "resolved", "outcome": "resolved", "workflowId": "...", "createdAt": "...", "lastActivityAt": "..." }, "turns": [ { "turnNumber": 1, "triggerType": "inbound_message", "messages": [{ "direction": "inbound", "body": "When will order 4521 arrive?", "attachments": [] }], "orchestratorIterations": [{ "iteration": 1, "action": "dispatch", "reasoning": "order status lookup", "agents": [{ "agentName": "Order Lookup" }] }], "specialistExecutions": [ { "agentName": "Order Lookup", "status": "completed", "model": "...", "toolCalls": [{ "toolName": "get_order", "policyDecision": "allow", "durationMs": 240 }] } ], "composedReply": { "messageText": "Order 4521 ships tomorrow.", "validationOutcome": "approved", "validationIssues": [] } } ], "activityTrace": [{ "activityType": "runOrchestrator", "status": "completed", "durationMs": 1830 }], "attentionItems": [], "identityEvents": [], "warnings": []}The report is assembled from several services. If one is briefly unavailable, its section is omitted and a note is added to warnings; the rest of the report is still returned.