curl --request POST \
--url https://api.orbit.devotel.io/api/v1/jambonz/call-status \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"call_sid": "5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c",
"call_status": "completed",
"direction": "inbound",
"from": "+14155550132",
"to": "+14155550100",
"duration": 42,
"hangup_reason": "normal"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/jambonz/call-status"
payload = {
"call_sid": "5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c",
"call_status": "completed",
"direction": "inbound",
"from": "+14155550132",
"to": "+14155550100",
"duration": 42,
"hangup_reason": "normal"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
call_sid: '5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c',
call_status: 'completed',
direction: 'inbound',
from: '+14155550132',
to: '+14155550100',
duration: 42,
hangup_reason: 'normal'
})
};
fetch('https://api.orbit.devotel.io/api/v1/jambonz/call-status', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orbit.devotel.io/api/v1/jambonz/call-status",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'call_sid' => '5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c',
'call_status' => 'completed',
'direction' => 'inbound',
'from' => '+14155550132',
'to' => '+14155550100',
'duration' => 42,
'hangup_reason' => 'normal'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/jambonz/call-status"
payload := strings.NewReader("{\n \"call_sid\": \"5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c\",\n \"call_status\": \"completed\",\n \"direction\": \"inbound\",\n \"from\": \"+14155550132\",\n \"to\": \"+14155550100\",\n \"duration\": 42,\n \"hangup_reason\": \"normal\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.orbit.devotel.io/api/v1/jambonz/call-status")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"call_sid\": \"5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c\",\n \"call_status\": \"completed\",\n \"direction\": \"inbound\",\n \"from\": \"+14155550132\",\n \"to\": \"+14155550100\",\n \"duration\": 42,\n \"hangup_reason\": \"normal\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/jambonz/call-status")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"call_sid\": \"5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c\",\n \"call_status\": \"completed\",\n \"direction\": \"inbound\",\n \"from\": \"+14155550132\",\n \"to\": \"+14155550100\",\n \"duration\": 42,\n \"hangup_reason\": \"normal\"\n}"
response = http.request(request)
puts response.read_body{
"status": "ok"
}Ingest a call lifecycle status event
Internal jambonz status-hook and the highest-volume voice callback — it fires on every call lifecycle transition (initiated, ringing, answered, and the terminal completed / failed / no-answer event). The handler attributes the leg to an organization, upserts the call_logs and sip_active_calls rows, finalizes billing on the terminal event, and pushes live updates to the softphone SSE channel. Signed with the jambonz webhook HMAC and not intended for direct client use. Bounded by a handler deadline and fails OPEN with a 200 ack so a transient blip never bounces the webhook or trips the edge 5xx alarm.
curl --request POST \
--url https://api.orbit.devotel.io/api/v1/jambonz/call-status \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"call_sid": "5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c",
"call_status": "completed",
"direction": "inbound",
"from": "+14155550132",
"to": "+14155550100",
"duration": 42,
"hangup_reason": "normal"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/jambonz/call-status"
payload = {
"call_sid": "5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c",
"call_status": "completed",
"direction": "inbound",
"from": "+14155550132",
"to": "+14155550100",
"duration": 42,
"hangup_reason": "normal"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
call_sid: '5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c',
call_status: 'completed',
direction: 'inbound',
from: '+14155550132',
to: '+14155550100',
duration: 42,
hangup_reason: 'normal'
})
};
fetch('https://api.orbit.devotel.io/api/v1/jambonz/call-status', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orbit.devotel.io/api/v1/jambonz/call-status",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'call_sid' => '5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c',
'call_status' => 'completed',
'direction' => 'inbound',
'from' => '+14155550132',
'to' => '+14155550100',
'duration' => 42,
'hangup_reason' => 'normal'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/jambonz/call-status"
payload := strings.NewReader("{\n \"call_sid\": \"5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c\",\n \"call_status\": \"completed\",\n \"direction\": \"inbound\",\n \"from\": \"+14155550132\",\n \"to\": \"+14155550100\",\n \"duration\": 42,\n \"hangup_reason\": \"normal\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.orbit.devotel.io/api/v1/jambonz/call-status")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"call_sid\": \"5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c\",\n \"call_status\": \"completed\",\n \"direction\": \"inbound\",\n \"from\": \"+14155550132\",\n \"to\": \"+14155550100\",\n \"duration\": 42,\n \"hangup_reason\": \"normal\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/jambonz/call-status")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"call_sid\": \"5f9c3b1a-2d4e-4f6a-8b0c-1e2d3f4a5b6c\",\n \"call_status\": \"completed\",\n \"direction\": \"inbound\",\n \"from\": \"+14155550132\",\n \"to\": \"+14155550100\",\n \"duration\": 42,\n \"hangup_reason\": \"normal\"\n}"
response = http.request(request)
puts response.read_body{
"status": "ok"
}Authorizations
Dashboard JWT token from Clerk
Body
jambonz call SID of the leg this event belongs to.
Lifecycle status (e.g. trying, ringing, in-progress, completed).
Call direction.
Caller number.
Called number.
Call duration in seconds (terminal events).
Reason the call ended (terminal events).
Response
Acknowledged. Returns status: ok once the lifecycle event has been recorded (or safely absorbed on a transient dependency fault).