# Webhooks

The Sinch Voice platform delivers real-time call event notifications to a configured webhook URL via HTTP POST requests.
The receiving endpoint responds with [SVAML commands](/docs/voice-2.0/api-reference/svaml) that control the ongoing call flow.



## Call webhook

 - [POST call.webhook](https://developers.sinch.com/docs/voice-2.0/api-reference/voice/webhooks/callwebhook.md): 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 :


| Element | Description |
| --- | --- |
| ` | 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. |
|  | 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}


| Part | Value |
| --- | --- |
| Method | The 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

json
{"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.

