Webhooks
Receive realtime events from Orbitali during calls.
Orbitali sends webhook events to an agent's Server URL while a call is active.
Each request includes the event name in the x-orbitali-event-type header and in message.type.
If the agent has a Server Secret, Orbitali also includes x-orbitali-signature. The value is sha256= followed by the lowercase hex HMAC-SHA256 digest of the raw JSON request body, using the Server Secret as the key.
Verify signatures in TypeScript
Set the same secret as the agent's serverSecret and in your webhook app, for example ORBITALI_WEBHOOK_SECRET. Verify the signature against the raw request body before parsing JSON.
import { createHmac, timingSafeEqual } from "node:crypto";
import { NextResponse } from "next/server";
export const runtime = "nodejs";
function verifyOrbitaliSignature({
secret,
rawBody,
signature,
}: {
secret: string;
rawBody: string;
signature: string | null;
}) {
if (!signature?.startsWith("sha256=")) {
return false;
}
const actual = signature.slice("sha256=".length);
if (!/^[a-f0-9]{64}$/i.test(actual)) {
return false;
}
const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
const actualBuffer = Buffer.from(actual, "hex");
const expectedBuffer = Buffer.from(expected, "hex");
return (
actualBuffer.length === expectedBuffer.length &&
timingSafeEqual(actualBuffer, expectedBuffer)
);
}
export async function POST(request: Request) {
const secret = process.env.ORBITALI_WEBHOOK_SECRET?.trim();
const rawBody = await request.text();
if (
!secret ||
!verifyOrbitaliSignature({
secret,
rawBody,
signature: request.headers.get("x-orbitali-signature"),
})
) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
let event: unknown;
try {
event = JSON.parse(rawBody);
} catch {
return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
}
if (
typeof event === "object" &&
event !== null &&
"message" in event &&
event.message &&
typeof event.message === "object" &&
"type" in event.message &&
event.message.type === "agent:tool-call"
) {
return NextResponse.json({ ok: true });
}
return NextResponse.json({ error: "Unsupported event" }, { status: 400 });
}
Events
| Event | When it is sent |
|---|---|
agent:assistant-request | Before the call starts when an agent uses a dynamic prompt |
agent:tool-call | When the model requests one of the agent's tools |
Assistant request
Use agent:assistant-request to build the prompt and greeting from your own data.
{
"message": {
"type": "agent:assistant-request",
"call": {
"id": "call_123",
"agentId": "agent_123",
"accountId": "account_123",
"phoneNumberId": "phone_123",
"channel": "voice",
"direction": "inbound",
"fromNumber": "+15551234567",
"toNumber": "+15557654321",
"startedAt": "2026-05-14T12:00:00.000Z"
}
}
}
Return the resolved prompt and optional greeting.
{
"prompt": "You are the receptionist for Acme Clinic. Help callers book appointments.",
"greeting": "Thanks for calling Acme Clinic. How can I help?"
}
Tool call
Use agent:tool-call to execute a model-requested action.
{
"message": {
"type": "agent:tool-call",
"call": {
"id": "call_123",
"agentId": "agent_123",
"accountId": "account_123"
},
"toolCall": {
"id": "tool_123",
"name": "check_availability",
"arguments": {
"date": "2026-05-14",
"time": "15:00"
}
}
}
}
Return a JSON object the model can use.
{
"available": true,
"slots": ["15:00", "15:30"]
}
Operational expectations
- Serve the endpoint over HTTPS.
- Verify
x-orbitali-signatureagainst the raw request body when using a Server Secret. - Keep responses fast; callers are waiting in realtime.
- Return structured JSON for success and errors.
- Avoid exposing secrets in tool responses because the model may speak relevant details back to the caller.
Privacy-safe webhook handling
- Treat call metadata, tool arguments, tool responses, and dynamic prompt inputs as customer-controlled personal data.
- Avoid logging raw request bodies in production. Log event type, call ID, tool name, status, latency, and a request correlation ID instead.
- Store only the fields your application needs to complete the workflow, and set a retention period for any copied webhook payloads.
- Redact or hash caller phone numbers before writing application logs unless the raw number is required for routing, fraud prevention, billing, or support.
- Do not return access tokens, credentials, internal IDs, medical details, payment details, or other secrets in tool responses.
- Keep
serverSecretandORBITALI_WEBHOOK_SECREToutside source control and rotate them after suspected exposure. - If callers opt out or do not consent to recording/transcription, make your webhook path avoid storing prompt context or tool payloads tied to that call.