Skip to content

Webhooks

End-of-call report

The webhook OnCore sends to your server when a call finishes.

When a call ends, OnCore POSTs an end-of-call-report event to your server with everything about the call: transcript, summary, timing, recording, and outcome data. This is the primary way to sync call results into your own systems.

Delivery#

The report is sent as an HTTP POST with a JSON body to your configured webhook URL:

  • The assistant's serverUrl if set (per-assistant override), otherwise
  • your tenant-level server URL.

Delivery is currently not retried: if your endpoint is down or returns a non-2xx status, that report is not redelivered. Respond quickly with a 2xx and process asynchronously.

Verifying requests#

Every delivery includes your client server secret (shown on the API Keys page) in a header. Compare it against the value you have on file and reject mismatches:

Request headers
POST /your-webhook-endpoint HTTP/1.1
Content-Type: application/json
x-sadie-core-secret: YOUR_CLIENT_SERVER_SECRET
Express example
app.post("/sadie/webhooks", (req, res) => {
  if (req.header("x-sadie-core-secret") !== process.env.SADIE_CLIENT_SERVER_SECRET) {
    return res.status(401).end();
  }
  const event = req.body;
  if (event.type === "end-of-call-report") {
    // persist transcript, summary, recording_url, ...
  }
  res.status(200).end();
});

Payload#

FieldTypeDescription
typestringAlways end-of-call-report
timestampnumberUnix time in milliseconds when the event was produced
call_idstringUnique call identifier
tenant_idstringYour tenant
assistant_idstringThe assistant that handled the call
customer_numberstringThe caller's number
restaurant_numberstringThe OnCore number that was called
transcriptstringFull call transcript
summarystringAI-generated call summary
messagesarrayTurn-by-turn messages
duration_secondsnumberCall duration in seconds
duration_minutesnumberCall duration in minutes
started_at / ended_atstringCall start / end times
recording_urlstringCall recording location ("NA" when no recording is available)
categorystringPrimary call category
category_listarrayAll matched categories
transfer_reason_idstringSet whenever a transfer was attempted during the call (regardless of ended_reason); omitted when no transfer occurred
supervisor_answeredboolean | nullTransfer outcome: true if the transferred call was answered (voicemail counts as answered), false if it went unanswered (no-answer, busy, failed, or canceled), null when there is no transfer outcome to report (typically the call had no transfer)
ended_reasonstringWhy the call ended. An open string; see Why a call ended below.
extraobjectAdditional outcome data (tags, CSAT rating/feedback, SMS reason)

A companion assistant-request event fires when a call starts, with the same identifiers (call_id, assistant_id, customer_number, call_source). It is useful for pre-loading customer context before the call ends.

Reacting to missed transfers#

On a warm-return transfer, supervisor_answered: false means the destination never picked up and the caller came back to the assistant. What the caller hears at that moment is configurable via the assistant's warmReturnMessage.

false is not the whole story for missed hand-offs

This field records whether the call connected, and a voicemail box connects, so a destination whose answering machine picks up reports supervisor_answered: true. Warm-return still returns the caller in that case (see Transfers), so alerting only on false silently misses every hand-off that went to voicemail.

Call recording & transcripts explains what is captured and why. To build a receiver for this payload step by step, follow Receive call results on your server.

Transfers explains the three modes and which of them can produce a return.

Why a call ended#

ended_reason is an open string, not a closed enum, so treat an unrecognised value as "other" rather than failing on it. Four values are set by OnCore itself and are the ones worth branching on:

ValueWhat happened
assistant-ended-callThe assistant ended the call deliberately: it decided the conversation was finished.
assistant-forwarded-callThe call was handed to a transfer destination. The assistant's leg ended because the call left it, which is a success, not a failure.
silence-timed-outThe caller stopped responding and idle handling ran out. Tunable with idleTimeoutSeconds and idleMessageMaxSpokenCount.
agent-waited-aloneNobody ever joined. The assistant answered and the far end never connected. Worth alerting on, because it usually means a routing or telephony problem rather than a caller who hung up.

Anything else comes from the telephony layer and is passed through unchanged: normal hang-ups, unreachable numbers, and trunk failures all surface here under their own names. One more OnCore value, disconnect_reason_null, means the call ended without the underlying layer reporting a cause. It is rare, and not itself a fault.

Do not treat assistant-forwarded-call as a dropped call

It is the most commonly misread value. A successful transfer always ends the assistant's leg, so a dashboard counting "calls that ended early" will count every hand-off unless it excludes this. Pair it with transfer_reason_id, which is set whenever a transfer was attempted, and with the caveat about supervisor_answered above.

Next steps#