Skip to content
Last updated

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. The signature is included in the authorization header of the request.

    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] ) )
Pseudocode ComponentDescription
CanonicalizedHeadersThe only required header is x-timestamp.
CanonicalizedResourceThe path to the API resource. For example, /v2/projects/{projectId}/calls.
Service ID/Service KeyThe Id/Key for your Programmable Voice Service can be found on your dashboard, under Configure call behaviour.
Service SecretThe secret for your Programmable Voice Service can also be found on your dashboard.

Timestamp

The client must send a custom header x-timestamp (time) with each request that's validated by the server. This custom header is used to determine that the request is not too old. The timestamp is also part of the signature. The timestamp must be formatted to ISO 8061 specifications.

Important!

The timestamp must be in the Coordinated Universal Time (UTC) timezone.

Example

Example of timestamp header
x-timestamp: 2026-06-02T15:39:31.2729234Z

Webhook Signature Validation Example

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

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

    Headers: 
    {
        host: 'yourdomain.com',
        'content-length': '724',
        authorization: 'service 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: service 669E367E-6BBA-48AB-AF15-266871C28135:Tg6fMyo8mj9pYfWQ9ssbx3Tc1BNC87IEygAfLbJqZb4=
Important!

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

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.

We'd love to hear from you!
Rate this content: