What are webhooks
Webhooks are user-defined HTTP callback that notifies you about any action that has taken place.
YCloud uses webhooks to push real-time notifications to your applications. By configuring webhooks and subscribing to specific events, you can receive event notifications and use these notifications to execute actions in your backend systems.
Steps to receive webhooks
You can start receiving event notifications in your applications using the steps in this section:
- Identify the events to monitor and the event payloads to parse.
- Create a webhook endpoint.
- Handle requests from YCloud by parsing each event and returning
2xx
response status codes. - Secure your webhooks (recommended)
Step 1: Identify the events to monitor
Each event corresponds to a certain set of actions that can happen to your account. For example, if you subscribe to the sms.message.updated
event you'll receive detailed payloads every time an SMS message is updated with a new status.
For a complete list of available webhook events and their payload examples, see Webhook Events & Payloads. See also Test webhooks for the detailed structured payload object.
Step 2: Create a webhook endpoint
You can use the Webhook Endpoints APIs, or go to Dashboard → Developers → Webhooks to manage webhooks.
Step 3: Handle requests from YCloud
Check event objects
Each event is structured as an event object with common properties: id
, type
, apiVersion
, and createTime
, and also contains properties unique to the event depending on type
.
Here is an example of an event with type
= whatsapp.message.updated
:
{
"id": "evt_eEVCy8eNqD9EvcFI",
"type": "whatsapp.message.updated",
"apiVersion": "v2",
"createTime": "2023-02-22T12:00:00.000Z",
"whatsappMessage": {
"id": "63f5d602367ea403f8175a6c",
"wamid": "wamid.BgNODYxN...",
"status": "failed",
"errorCode": "100",
"errorMessage": "Parameter Invalid",
"whatsappApiError": {
"message": "(#100) Invalid parameter",
"type": "OAuthException",
"code": "100",
"fbtrace_id": "AwmiSOCojlAkqvjCTjGt37r",
"error_data": {
"messaging_product": "whatsapp",
"details": "Parameter Invalid"
}
},
"totalPrice": 0.0,
"currency": "USD",
"bizType": "whatsapp"
}
}
Return a 2xx response
Your endpoint must quickly return a successful HTTP status (e.g., 200
) before any complex logic that could cause a timeout.
Build-in retries
If YCloud doesn't quickly receive a 2xx
response for an event, we'll retry several times in the next few hours. Currently, we retry up to 7 times, with intervals of 10s, 30s, 5m, 30m, 1h, 2h, 2h.
Step 4: Secure your webhooks (recommended)
YCloud can sign the webhook events by including a signature in the HTTP header YCloud-Signature
. This allows you to verify that the events were sent by YCloud, not by a third party.
The YCloud-Signature
header contains a Unix Timestamp and a signature generated by HMAC with SHA-256.
YCloud-Signature: t=1654084800,s=8eb70f2acb056c2119acbee8fdd98a889021d9c268bc9ad248a4182c40e31119
Verify the signature by the following steps:
Step 1: Extract the timestamp and signatures from the header
Split the header, using the ,
character as the separator, to get a list of elements. Next, split each element, using the =
character as the separator, to get a prefix and value pair.
The value for the prefix t
corresponds to the timestamp and s
corresponds to the signature.
Step 2: Prepare the signed payload string
The signed payload string is created by concatenating:
- The timestamp (as a string)
- The character
.
- The actual JSON payload (that is, the request body)
For example:
1654084800.{"id":"evt_eEVCy8eNqD9EvcFI","type":"whatsapp.message.updated","apiVersion":"v2","createTime":"2023-02-22T12:00:00.000Z","whatsappMessage":{"id":"63f5d602367ea403f8175a6c","wamid":"wamid.BgNODYxN...","status":"failed","errorCode":"100","errorMessage":"Parameter Invalid","whatsappApiError":{"message":"(#100) Invalid parameter","type":"OAuthException","code":"100","fbtrace_id":"AwmiSOCojlAkqvjCTjGt37r","error_data":{"messaging_product":"whatsapp","details":"Parameter Invalid"}},"totalPrice":0,"currency":"USD","bizType":"whatsapp"}}
Step3: Determine the expected signature
Before you can verify signatures, you need to retrieve your endpoint's secret by the Retrieve a webhook endpoint API.
Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the signed payload string as the message.
// Using library commons-codec (https://central.sonatype.com/artifact/commons-codec/commons-codec)
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
public class MainClass {
public static void main(String[] args) {
String signedPayload = timestamp + "." + body;
HmacUtils hmacUtils = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secret);
String expected = hmacUtils.hmacHex(signedPayload);
System.out.println(expected);
}
}
const crypto = require('crypto');
const toBeSignedPayload = timestamp + '.' + body
const expected = crypto.createHmac('sha256', secret)
.update(toBeSignedPayload)
.digest("hex");
using System;
using System.Security.Cryptography;
using System.Text;
class MainClass {
public static void Main (string[] args) {
string toBeSignedPayload = timestamp + "." + body;
byte[] secretBytes = Encoding.UTF8.GetBytes(secret);
byte[] messageBytes = Encoding.UTF8.GetBytes(toBeSignedPayload);
HMACSHA256 cryptographer = new HMACSHA256(secretBytes);
byte[] expectedBytes = cryptographer.ComputeHash(messageBytes);
string expected = BitConverter.ToString(expectedBytes).Replace("-", "").ToLower();
Console.WriteLine(expected);
}
}
import json
import hmac
import hashlib
signed_payload = f'{timestamp}.{body}'
expected = hmac.new(
key=secret.encode(),
msg=signed_payload.encode(),
digestmod=hashlib.sha256
).hexdigest()
print(expected)
Step 4: Compare the signatures
Compare the signature in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.