# Webhook Request Signing

The Sinch Platform can initiate webhook requests to an URL you define (*Webhook URL*) on events like call.incoming, call.answered, call.hangup and more.
All Webhook requests are signed using your Service access key and secret pair found on your [dashboard](https://dashboard.sinch.com/voice-v2/services). The signature is included in the `authorization` header of the request.

```shell
    authorization = "service" + " " + serviceKey + ":" + Signature

    Signature = Base64 ( HMAC-SHA256 ( Base64-Decode( serviceSecret ), UTF8 ( StringToSign ) ) );

    StringToSign = HTTP-Verb + "\n" +
        Content-MD5 + "\n" +
        content-type + "\n" +
        CanonicalizedHeaders + "\n" +
        CanonicalizedResource;

    Content-MD5 = Base64 ( MD5 ( [BODY] ) )
```

## Example

In this example, assume that the *Webhook URL* is configured as `"https://yourdomain.com/sinch/webhook"`

```shell
    serviceKey = 669E367E-6BBA-48AB-AF15-266871C28135
    serviceSecret = BeIukql3pTKJ8RGL5zo0DA==

    Heather: 
    {
        host: 'yourdomain.com',
        'content-length': '724',
        authorization: 'application XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
        baggage: 'SessionId+=+01KTSPWJP2YPH9KSAKC2SRP7W8',
        'ce-id': '55f0102b-739a-4151-8caf-9b3aaf249859',
        'ce-source': 'projects/727ce3a0-b9ac-4b65-8a53-29e4e0d5c270/services/b7430a33-38c8-4fba-9fb7-c66eae501d11',
        'ce-specversion': '1.0',
        'ce-time': '2026-06-10T21:27:04.0783345+00:00',
        'ce-type': 'com.sinch.voice.webhook.v2',
        'content-type': 'application/json; charset=utf-8',
        traceparent: '00-5a8c4644667b4b60784f22c0544d335d-701eb65af934e502-01',
        'x-forwarded-for': '15.228.118.128',
        'x-forwarded-host': 'yourdomain.com',
        'x-forwarded-proto': 'https',
        'x-timestamp': '2026-06-10T21:27:04.1466768Z',
        'accept-encoding': 'gzip'
    }

    Body:
    {
    event: 'call.webhook.call.answered',
    call: {
        callId: '01KTSPWYAFT6MZ3TM7H43K82VQ',
        serviceId: 'b7430a33-38c8-4fba-9fb7-c66eae501d11',
        projectId: '727ce3a0-b9ac-4b65-8a53-29e4e0d5c270',
        sessionId: '01KTSPWHMJGTPV36FSBY7C6Z44',
        to: {
            type: 'STREAM', stream: [Object] 
            },
        direction: 'OUTBOUND',
        callResult: 'IN_PROGRESS',
        callType: 'STREAM',
        originationType: 'SERVER',
        startTime: '2026-06-10T21:27:02.6695935',
        answerTime: '2026-06-10T21:27:03.865752',
        updateTime: '2026-06-10T21:27:03.865752',
        callRate: { 
            currencyCode: 'EUR',
            amount: 0.0028
            },
        callResourceUrl: '/v2/projects/727ce3a0-b9ac-4b65-8a53-29e4e0d5c270/calls/01KTSPWYAFT6MZ3TM7H43K82VQ'
        }
    }


    Content-MD5 = Base64 ( MD5 ( [BODY] ) )
        REWF+X220L4/Gw1spXOU7g==

    StringToSign
        POST
        REWF+X220L4/Gw1spXOU7g==
        application/json
        x-timestamp:2014-09-24T10:59:41Z
        /sinch/webhook

    Signature = Base64 ( HMAC-SHA256 ( Base64-Decode( serviceSecret ), UTF8 ( StringToSign ) ) )
        Tg6fMyo8mj9pYfWQ9ssbx3Tc1BNC87IEygAfLbJqZb4=

    HTTP Authorization Header
        authorization: application 669E367E-6BBA-48AB-AF15-266871C28135:Tg6fMyo8mj9pYfWQ9ssbx3Tc1BNC87IEygAfLbJqZb4=
```

Important!
The service Secret value must be base64-decoded from before it's used for signing.

Note:
HTTP headers are case-insensitive, so you don't need to worry about casing.

## Webhook Request Validation

Your development platform that receives the Webhooks can verify that the request originated from Sinch by calculating the signature as described above and compare the result with the value contained in the `service` HTTP header.