Webhooks allow you to listen for changes in a SavvyCal account and get notified via HTTP POST requests.
Navigate to Settings > Integrations and click the + icon in the Webhooks:
See the Webhooks endpoints documentation for managing webhooks via the SavvyCal API.
When an event occurs that triggers a webhook, we will send an HTTP POST to the URL you specified, with a JSON-encoded body:
POST /my-webhook-receiver HTTP/1.1
Host: https://myapp.com
User-Agent: SavvyCal Webhooks (https://savvycal.com)
x-savvycal-signature: sha256=6CAA4DEF5C3463B785E885FF19B8987B348E19399D2C5FB291274EDFA7128105
Content-Type: application/json
{
"type": "event.created",
"id": "payload_XXXXXXXXXX",
[...]
}
The URL you specify to received webhook payloads should respond quickly with a 200 OK
response code. To ensure you respond in a timely manner, it’s best to enqueue the body in a job queue to process asynchronously (rather than processing it in the request cycle). If we receive a non-2xx response code, we will retry with exponential backoff.
Webhooks are sent over HTTPS and are signed with a secret key. The secret key is unique to each webhook and is used to verify the authenticity of the requests. This secret can be found alongside the webhook configuration in your account’s integration settings. Using the secret key, SavvyCal signs the request body with a SHA-256 HMAC signature. The signature is included in the x-savvycal-signature
header.
Click here to copy your signing secret to clipboard:
Therefore, you can verify the authenticity of a webhook request you receive by generating your own signature (with your webhook’s secret key) and comparing it to the signature in the x-savvycal-signature
header.
An example of how to verify the signature is shown below in Elixir:
def verify_signature(body, signature, secret) do
body = Plug.Conn.read_body(conn)
header_signature = Plug.Conn.get_req_header(conn, "x-savvycal-signature") |> List.first()
computed_signature =
:sha256
|> :crypto.hmac(secret, body)
|> Base.encode16()
# Performs a "constant time" string comparison, which helps mitigate certain
# timing attacks against regular equality operators.
Plug.Crypto.secure_compare(header_signature, computed_signature)
end