Inbound Call Webhook Validation
Inbound Call Webhook Validation
Some external systems that send webhooks require you to validate the webhook URL before saving it (and even during the webhook usage). One examples of such system is Zoom. Basically, the external system makes a POST request to your endpoint with a challenge request body. After your endpoint receives the request, it needs to answer in a specific way to prove you own the endpoint.
Declarative Webhooks supports webhook validation. When you define an Inbound Call Template, in the first step of the wizard, under the “Advanced” section, you can define the condition to determine if it’s a challenge request body and the apex class to respond to the validation request.
Webhook Validation Condition
The Webhook Validation Condition input requires a formula to determine if the received body is a challenge request or a normal request. If the formula returns true when an inbound call is received, the class mentioned in the Webhook Validation Class field is used to determine the inbound call response body. Otherwise, the normal inbound call flow takes place.
In the formula, you can reference:
- nodes from the JSON body using this format: NODE:”nodepath”
- header values using this format: HEADER:”headername”
- URL parameters using this format: PARAM:”urlparamname”
For example, looking at the Zoom documentation, we can use this entry in the input field to determine if the request body is a challenge. It returns true if the event node value equals “endpoint.url_validation”.
NODE:"event" = "endpoint.url_validation"
Webhook Validation Class
If the condition in the Webhook Validation Condition input passes, you can specify a class to generate the response. The class needs to be global, extend the d_wh.WebhooksValidationCallable class and impement the Validate method:
global class SampleVerification extends d_wh.WebhooksValidationCallable { global override string Validate(Map<String, String> parameters, Map<String, String> headers, String requestBody) { return 'responseBody'; } }
The parameters parameter contains all the URL paramaters as a map.
The headers parameter contains all the request headers.
The requestBody contains the request body as a string.
You need to return the string to be used as a response body.
For example, the class below can be used for Zoom webhook validation:
global class ZoomVerification extends d_wh.WebhooksValidationCallable { global override string Validate(Map<String, String> parameters, Map<String, String> headers, String requestBody) { Map<String, Object> requestMap = (Map<String, Object>)JSON.deserializeUntyped(requestBody); string plainToken = (String)((Map<String, Object>)requestMap.get('payload')).get('plainToken'); string encryptedToken = EncodingUtil.convertToHex(Crypto.generateMac('HmacSHA256', Blob.valueOf(plainToken), Blob.valueOf(Label.Zoom_Token))); Map<String, Object> returnMap = new Map<String, Object>(); returnMap.put('plainToken', plainToken); returnMap.put('encryptedToken', encryptedToken); return JSON.serialize(returnMap); } }