Skip to content

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.

Retrieve conversations for a workspace, optionally filtered by status or contact.

Terminal window
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:

ParameterTypeRequiredDescription
workspaceIdUUIDNoFilter by workspace
statusstringNoFilter by status: open, in_progress, awaiting_contact, resolved, closed, abandoned
contactIdUUIDNoFilter by contact
accountIdUUIDNoFilter by account
qstringNoFree-text search across contact name / email / subject
humanManagedbooleanNoFilter to conversations currently owned by a human operator
assigneestringNoFilter 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)
hasAttentionbooleanNoFilter to conversations with one or more open attention items
limitintegerNoPage size (default 50, max 100)
cursorstringNoOpaque 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.

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.

Terminal window
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.

Retrieve the message history for a conversation, ordered chronologically.

Terminal window
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.

Retrieve attachments for a conversation.

Terminal window
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"
}
]

Send a human-authored reply. This signals the conversation workflow to deliver the message via the original channel.

Required scope: conversations:write

Terminal window
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
}

Mark a conversation as resolved, optionally with an outcome description.

Required scope: conversations:write

Terminal window
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
}

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

Terminal window
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/take-over" \
-H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"

Release a taken-over conversation back to the agent pipeline. The platform resumes processing on the next inbound message.

Required scope: conversations:write

Terminal window
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/release" \
-H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"

Start a new outbound conversation. This creates a conversation, resolves or creates the contact, and delivers the first message.

Required scope: conversations:write

Terminal window
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 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.

Terminal window
curl "https://api.ohallo.eu/api/attention-items?workspaceId=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"

Query parameters:

ParameterTypeRequiredDescription
workspaceIdUUIDNoFilter to a single workspace
statusstringNoopen, acknowledged, resolved, or dismissed (default returns all)
conversationIdUUIDNoFilter 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.

Terminal window
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 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

Terminal window
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.

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

Terminal window
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/unassign" \
-H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"

Approve a guardrail-gated tool call waiting for human approval. Resumes the agent pipeline.

Required scope: conversations:write

Terminal window
curl -X POST "https://api.ohallo.eu/api/conversations/c9f8e7d6-b5a4-3210-fedc-ba9876543210/approve" \
-H "Authorization: Bearer sf_live_v1_a3Bx9kLmP2qR7wYz4nDfGhJkQpStUvWx"

Get aggregate conversation counts by status for a workspace.

Required scope: conversations:read

Terminal window
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
}

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

Terminal window
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.