call.failed
The last event of a call that was not answered or could not connect, POSTed to the number's events_url.
The last event of a call that was not answered or could not connect, POSTed to the number's events_url.
call.failed is the last event of a call that never connected. Its callSessionState is Completed and its status says why. Unanswered, busy, cancelled and failed calls are not charged.
Call events are POSTed to the events_url on the number's routing, which you set with PUT /v1/numbers/{id}/routing. They are not workspace webhooks: you cannot subscribe to them with POST /v1/webhooks.
The body is flat JSON.
{
"callSessionState": "Completed",
"direction": "Outbound",
"sessionId": "HD_24d73b4518bc",
"clientDialedNumber": "+254720000000",
"destinationNumber": "+254720000001",
"callStartTime": "2026-06-27+10:00:00",
"durationInSeconds": "0",
"status": "NoAnswer",
"isActive": "0"
}| Field | Type | Description |
|---|---|---|
callSessionState | string | Completed for this event. |
direction | string | Inbound or Outbound. |
sessionId | string | The call's id, starting HD_. The same on every event of the call. GET /v1/calls/{id} accepts it. |
callerNumber | string | Who is calling. On an inbound call, the caller's number. |
clientDialedNumber | string | The number that was dialled. On an outbound call, the person you called. |
destinationNumber | string | Your Sautikit number, on inbound and outbound calls. |
callStartTime | string | When the call started. |
isActive | string | "1" while the call is live, "0" once it has ended. |
status | string | Why the call did not connect. See below. |
status is one of:
NoAnswer or Missed: nobody picked up.Busy: the line was busy.ORIGINATOR_CANCEL: whoever started the call hung up before it was answered.CALL_REJECTED): the call was rejected or could not be routed. Treat any value other than Success as a failed call.Other fields may be present.
events_url one time and is not retried. Respond within 5 seconds; the response body is ignored.X-Sautikit-* headers and no signature. Use an events_url with a path that is hard to guess, and confirm anything that matters with GET /v1/calls/{id}, passing the sessionId.callSessionState says which one it is.import express from "express";
const app = express();
app.use(express.json());
app.post("/sautikit/events", (req, res) => {
res.sendStatus(200); // answer first, then do the work
const event = req.body;
if (event.callSessionState === "Completed" && event.status !== "Success") {
console.warn(`Call ${event.sessionId} did not connect: ${event.status}`);
// retry later, or alert your team
}
});events_url with PUT /v1/numbers/{id}/routing.GET /v1/calls/{id}.