Skip to content

Webhooks

End-of-conversation report

The webhooks OnCore sends when a messaging conversation starts and ends.

Messaging channels (SMS, web chat) have their own mirror of the voice webhooks. When a conversation starts, OnCore POSTs an assistant-request event; when it ends, an end-of-conversation-report with the transcript, summary, and analysis. The payloads are keyed with a conversation_id instead of a call_id (that's how your endpoint tells a conversation from a call), and carry channel / customer_identifier in place of the voice-specific fields.

Delivery#

Sent as an HTTP POST with a JSON body to your configured webhook URL (the assistant's serverUrl if set, otherwise your tenant-level server URL), verified with the plaintext x-sadie-core-secret header, exactly like the voice webhooks. See the webhooks overview.

Delivery is currently not retried: respond quickly with a 2xx and process asynchronously.

Common fields#

Both events share this base:

FieldTypeDescription
typestringassistant-request (start) or end-of-conversation-report (end)
timestampnumberUnix time in milliseconds when the event was produced
customer_numberstringThe customer's phone number, where the channel has one
customer_identifierstringThe channel-appropriate customer identity (e.g. the visitor id for web chat)
channelstringThe messaging channel the conversation happened on
tenant_idstringYour tenant
assistant_idstringThe assistant that handled the conversation
conversation_idstringUnique conversation identifier: the messaging counterpart of call_id
restaurant_numberstringThe OnCore number the customer texted

assistant-request (conversation start)#

Carries only the common fields. As with the voice assistant-request, your JSON response is read on start (it can apply overrides) and ignored on end.

end-of-conversation-report (conversation end)#

Adds the outcome fields (all optional):

FieldTypeDescription
transcriptstringFull conversation transcript
summarystringAI-generated summary
messagesarrayTurn-by-turn messages
analysisobjectPass-through analysis, same shape as voice call analysis: { summary, structuredData: { category, category_list, technicalDifficultiesOccurred }, successEvaluation }. Forwarded verbatim, sentinel values included
started_at / ended_atstringConversation start / end times
ended_reasonstringWhy the conversation ended
Example payload
{
  "type": "end-of-conversation-report",
  "timestamp": 1753872000000,
  "customer_number": "+15555550111",
  "customer_identifier": "usr_abc123",
  "channel": "web",
  "tenant_id": "0195f1e2-1111-7000-8000-000000000000",
  "assistant_id": "0195f1e2-2222-7000-8000-000000000000",
  "conversation_id": "0195f1e2-4444-7000-8000-000000000000",
  "restaurant_number": "+15555550123",
  "transcript": "...",
  "summary": "...",
  "started_at": "2026-07-30T11:55:00.000Z",
  "ended_at": "2026-07-30T12:00:00.000Z",
  "ended_reason": "conversation-ended-by-user"
}

Current channel values are web, sms, and whatsapp. Current ended_reason values are:

ValueMeaning
conversation-idle-timeoutThe inactivity window elapsed
conversation-ended-by-userThe customer or web client explicitly ended it
conversation-ended-by-agentThe assistant ended it

Treat both fields as open enums: handle these values explicitly and keep an unknown fallback so an added channel or end reason does not break ingestion.

A short goodbye the customer sends right after the customer or the assistant ended a conversation (for example "thanks, you too!") does not open a new conversation, so it produces no second assistant-request and no second report. A real message in that window opens a new conversation, which ends with its own report.

Conversations are also readable via the API: see Conversations.

Next steps#