Skip to content

Call webhook
Webhook

Request

Receives webhook notifications for call events from the Voice Platform.

Request signing

Every webhook request is signed by the Voice Platform so that the receiving endpoint can verify that the request was sent by Sinch and was not altered in transit.

The signature is carried in the Authorization header, using the service authentication scheme. The header value is the service identifier and the signature, separated by a colon:

Authorization: service <serviceId>:<signature>
ElementDescription
<serviceId>Identifier of the service the webhook belongs to. Matches the serviceId segment of the ce-source header and the call.serviceId field of the request body.
<signature>Base64-encoded HMAC-SHA256 hash of the canonical request string, keyed with the service secret.

Signature

signature = Base64( HMAC-SHA256( secretBytes, UTF8(stringToSign) ) )

secretBytes is the 16-byte binary value of the service secret, and the signed message is the UTF-8 encoding of stringToSign.

The service secret is issued as a Base64 string, for example F5wrP9SKYU6w8sbZXkp7GA==. Base64-decoding it yields the 16 bytes of secretBytes. The decoded bytes are used as the HMAC key — signing with the characters of the Base64 string instead produces a different, invalid signature.

Canonical string

stringToSign is the concatenation of five parts. Each of the first four parts is terminated by a single line feed (\n); the last part is not followed by a line feed.

POST
{contentMd5}
{contentType}
x-timestamp:{timestamp}
{path}
PartValue
MethodThe HTTP method, always POST for webhook requests.
{contentMd5}Base64( MD5( UTF8(body) ) ) — the Base64-encoded MD5 digest of the raw request body. Empty when the request carries no body.
{contentType}The full value of the Content-Type header, including its parameters, for example application/json; charset=utf-8. Empty when the request carries no body.
{timestamp}The verbatim value of the x-timestamp request header, an ISO 8601 UTC timestamp with seven fractional-second digits, for example 2026-04-01T12:00:00.0000000Z. The literal prefix x-timestamp: is part of the canonical string.
{path}The absolute path of the configured webhook URL, without scheme, host, query string or fragment, for example /voice-webhooks.

The MD5 digest acts as a checksum of the body inside the canonical string. The integrity and authenticity guarantee is provided by the HMAC-SHA256 signature computed over that string.

The CloudEvents (ce-*) headers are not covered by the signature.

Example

A request delivered to https://example.com/voice-webhooks with the body

{"event":"call.incoming","call":{"callId":"01AN4Z07BY79KA1307SR9X4MV3"}}

Content-Type: application/json; charset=utf-8 and x-timestamp: 2026-04-01T12:00:00.0000000Z produces the canonical string

POST
CH5/FnzqzRJ81QlTLGAhAw==
application/json; charset=utf-8
x-timestamp:2026-04-01T12:00:00.0000000Z
/voice-webhooks

With the service secret F5wrP9SKYU6w8sbZXkp7GA==, the resulting header is

Authorization: service a74b1566-0f18-4f8e-9c23-8e6b5df8fd3e:EWFtVTrykdhMTdyYSbn40GBJpf5UBeggO9T99sdwLyY=

Verification

  1. Split the Authorization header value into the service identifier and the signature.
  2. Rebuild stringToSign from the received request, using the raw request body exactly as delivered, before any parsing, re-serialization or whitespace normalization.
  3. Recompute the signature with the secret of the identified service and compare it to the received value using a constant-time comparison.
  4. Reject the request when the two values differ.
  5. Reject requests whose x-timestamp lies outside an accepted clock-skew window, to limit replay of previously valid requests.
Security
BasicAuth or SinchOAuth2
Headers
ce-specversionstringrequired

CloudEvents specification version.

Value:"1.0"
ce-typestringrequired

CloudEvents event type.

Value:"com.sinch.voice.call.control.v1"
ce-sourcestringrequired

URI identifying the context where the event originated. Format: projects/{projectId}/services/{serviceId}.

Example:projects/5c5bf2b1-35ae-4825-ab89-457e07bb60e6/services/6e124178-c29d-46a5-943c-5c2ae544aade
ce-idstring, (uuid)required

Unique identifier for this event instance. Use together with ce-source for deduplication.

Example:cb0c6a68-53de-4590-94a1-6e95df89fbac
ce-timestring, (date-time)required

Timestamp (RFC 3339) when the event occurred.

Example:2026-04-01T12:00:00+00:00
x-timestampstringrequired

Timestamp (ISO 8601, UTC) applied by the Voice Platform when the request was signed. Covered by the Authorization signature and required to recompute it.

Example:2026-04-01T12:00:00.0000000Z
Bodyapplication/json
eventstringrequired
Example:"call.incoming"
One of:

Identifies the type of call event that triggered this webhook notification. Call-related webhook events always start with call. followed by the type of event that triggered them. Events triggered by the webhook SVAML command are dynamic and follow the pattern call.webhook.<webhookName>.

string
Enum ValueDescription
call.incoming

Triggered when an inbound call arrives on a service configured with a webhook URL.

call.answered

Triggered when an outbound call is answered by the recipient.

call.busy

Triggered when the outbound call recipient is busy.

call.rejected

Triggered when the outbound call is rejected by the recipient.

call.timeout

Triggered when the outbound call was not answered within the dial timeout.

call.hangup

Triggered when the call is disconnected.

call.failed

Triggered when the call could not be set up.

call.amd.human

Triggered when answering machine detection determines that a human answered the call.

call.amd.machine

Triggered when answering machine detection determines that a machine answered the call.

call.amd.beep

Triggered when answering machine detection detects a voicemail beep.

call.amd.unknown

Triggered when answering machine detection cannot determine whether a human, machine, or beep was detected.

call.message.finished

Triggered when all messages in a messages sequence have finished playing.

call.recording.finished

Triggered when a recording is successfully stopped. This event does not guarantee that the recorded file has been delivered to the configured destination yet.

call.recording.failed

Triggered when recording could not be started.

call.menu

Triggered when a menu completes and input is received from the user or the menu fails.

callobject(Call Resource)required

The current state of the call at the time the event was triggered.

menuobject

Information about the menu interaction that triggered the webhook, including the menu name and the input sequence received from the user.

This property is also included for webhooks triggered by the webhook command within a menu context.

Payload
{ "event": "call.incoming", "call": { "callId": "01AN4Z07BY79KA1307SR9X4MV3", "projectId": "5c5bf2b1-35ae-4825-ab89-457e07bb60e6", "serviceId": "a74b1566-0f18-4f8e-9c23-8e6b5df8fd3e", "sessionId": "01AN4Z07BY79KA1307SR9X4MV2", "direction": "INBOUND", "originationType": "PHONE", "callType": "PHONE", "from": { … }, "to": { … }, "callResult": "INITIATED", "startTime": "2025-06-01T10:00:00Z", "callRate": { … }, "callResourceUrl": "https://voice.api.sinch.com/v2/projects/5c5bf2b1-35ae-4825-ab89-457e07bb60e6/calls/01AN4Z07BY79KA1307SR9X4MV3" } }

Responses

Success. A SVAML document returned in response to a webhook.

Note: callName and events only take effect in responses to webhooks triggered by an incoming call. In responses to other webhook types, they are ignored.

Bodyapplication/json
commandsArray of objects, non-empty(SVAML Commands)required

The ordered list of SVAML commands to execute. Contains at least one command.

callNamestring, [ 1 .. 32 ] characters^\S+$

Name of the call.

Example:"incoming"
eventsobject

Commands to execute on specific events for this call.

Response
{ "callName": "incoming", "commands": [ { … } ] }
We'd love to hear from you!
Rate this content: