## Documentation Index Access the complete documentation index at: https://www.zoho.com/ae/books/help/llms.txt Use this file to discover all available documentation pages before proceeding. # Webhooks Webhooks facilitate communication with third-party applications by sending instant web notifications every time an event occurs in Zoho Books. With Webhooks, you can configure HTTP and HTTPS URLs and associate them with workflow rules to automate the notification process. Read our help document on [webhook examples](/ae/books/help/settings/using-webhook.html) to know more about when and how you can use webhooks. For general information about webhooks, visit [webhooks.org](https://webhooks.org). **Scenario:** Let’s say you use a separate fulfillment application to ship orders. Each time a sales order is created in Zoho Books, you want that application to receive the order details right away. By setting up a webhook with the application’s URL and associating it with a workflow rule, Zoho Books sends the order details to the application as soon as a sales order is created, so your team can start fulfillment without entering the data again. ## Create a Webhook To set up a webhook: * Go to **Settings** on the top right corner of the page. * Select **Workflow Actions** under _Automation_. * In the _Workflow Actions_ pane, select **Webhooks**. * Click **\+ New Webhook** in the top right corner. ![Click + New Webhook](/books/help/images/settings/webhooks/plus-new-webhook.png) * Fill in the necessary details for the following fields. Field Name Description **URL and Parameters** Enter the URL (URL of the external service provider’s API) and select the type of event for which the webhook has to be triggered. You can also insert placeholders by clicking the **\+ New Placeholder** button. Select the type of API method: PUT, POST, or DELETE. By default, the system selects the POST method. **POST**: Requests that the data sent must be considered as new. **PUT**: Requests that the data sent must be considered as the modified version of the existing version. **DELETE**: Requests that the data must be deleted. **Custom Parameters** You can add custom parameters in the webhook such as AuthToken, Security Token, API Key, etc., based on which the URL will be appended. Enter the required parameter under **Parameter Name** and the corresponding value under **Parameter Value**. If you want to add multiple parameters, click **\+ New Parameter**. **HTTP Headers** In the HTTP Header section, you can include any additional information that you want to be included in the HTTP request. Enter a key under **Parameter Name** and enter a value under **Parameter Value**. Click **\+ New Header** if you want to add additional headers. **Security Preferences** Select how you want to authorise access to the external service provider’s URL. **General**: Select this type if you want to create this webhook with basic authorisation, API authorisation, or without any authorisation. **Connections**: Select this type if you want to use a connection that was created between Zoho Books and a third-party application to authorise this webhook. You can also secure the webhook with a secret token, which cannot be edited or viewed once the webhook is created. Check the **I want to secure this webhook with a secret token** box and enter the secret token in the field below. This will help to verify whether the webhook was sent from Zoho Books. It should be alphanumeric and between 12 and 50 characters. **Body** In the Body section, choose how you want to send the data. You can choose from **Default Payload**, **x-www-form-urlencoded**, and **Raw** body parameters. **Default Payload**: In the default payload format, all the parameters associated with the module will be sent to the request body in the application/JSON format content type. **x-www-form-urlencoded**: In the x-www-form-urlencoded format, the data will be encoded and sent to the server. **Raw**: In the raw format, you can choose the parameters sent to the request body. The content type will be application/JSON. * Click **Save and Execute** to check if the webhook works properly, or click **Save** if you want to execute it later. **Note**: When you set up webhooks, all your contacts’ details in your Zoho Books organisation (name, phone number, address, and email address) will be shared with the URL you want to notify. * * * ## Associate Webhooks with Workflow Rules The webhooks you create should be associated with workflow rules so that they are triggered automatically when the required conditions are met. To associate webhooks with workflow rules: * Go to **Settings**. * Select **Workflow Rules** under _Automation_. * Click **\+ New Workflow Rule** in the top right corner. * Enter the necessary details. See [Workflow Rules](/ae/books/help/settings/automation/workflow-rules.html). * Under [**Actions**](/ae/books/help/settings/automation/workflow-rules.html#add-actions), choose **Webhooks** as the _Type_ and select the webhook you want to associate with the workflow rule. * Click **Save**. Now, whenever the criteria is met, the workflow rule will be triggered, which in turn will trigger the webhook. * * * ## Delivery Behaviour When a webhook is triggered, Zoho Books attempts to deliver it to your endpoint URL. The sections below explain how deliveries are evaluated, retried, and reported in [Workflow Logs](/ae/books/help/settings/automation/workflow-logs.html). ### Delivery Statuses Every webhook delivery results in one of these statuses in Workflow Logs: * **Success**: The endpoint responded with a 2xx status code within the timeout window. * **Failed**: The delivery received a non-2xx response or timed out. * **Skipped**: The delivery was not attempted, typically when the daily limit is reached. If a retry is scheduled for a failed delivery, the next retry time is displayed alongside the status. ### Timeout Behaviour The connection timeout is set at 5 seconds and the read timeout at 10 seconds. If either limit is breached, the attempt is marked as failed. ### What Counts as a Failure Any non-2xx response, including 3xx redirects, 4xx client errors, 5xx server errors, and timeouts, is treated as a failure and is eligible for retry. If your endpoint URL has a redirect configured, update the webhook URL to the final destination directly. ### Default Retry Policy Failed webhooks are automatically retried exactly 5 times before being marked as exhausted. Retried deliveries carry the same original payload, so design your endpoint to handle duplicate deliveries safely. ### Custom Retry Policy You can configure up to 20 retry attempts, along with a choice of retry method: **fixed interval** (the same wait time between each retry), **additive** (the wait time increases by a fixed amount after each retry), or **multiplicative** (the wait time is multiplied by a set factor after each retry). To set this up, open the **Webhooks** tab in [Configure Failure Preferences](/ae/books/help/settings/automation/workflow-logs.html#configure-failure-preferences) on the Workflow Logs page. ### Failure Notifications If a webhook fails 20 or more times consecutively, a notification is sent to the recipients configured under the **Webhooks** tab in [Configure Failure Preferences](/ae/books/help/settings/automation/workflow-logs.html#configure-failure-preferences) on the Workflow Logs page. ### Manual Retry Exhausted webhooks can be manually retried from [Workflow Logs](/ae/books/help/settings/automation/workflow-logs.html) at any time. Manual retries do not count against your organisation’s daily webhook limit, which varies by your Zoho Books plan. * * * ## Secure Your Webhooks Securing your webhooks can help verify that the webhooks were sent from Zoho Books. To do this, you have to set up your server so that it listens for webhooks from Zoho Books. When your server receives a webhook from Zoho Books, a hash value must be generated based on the payload and your secret token. Once done, check if it matches the hash value from Zoho Books and thereby validate the source of the webhook. This can add a layer of security by enabling your server to disregard third-party webhooks pretending to originate from Zoho Books. * * * ## Validate Webhooks When your server receives the webhook, a hash value will have to be generated for the payload in the same way that Zoho Books generated it. This is necessary to produce the same hash value to validate the webhook. The following parameters (if available) are used to generate the hash value: * Query string parameters. * Default payload or customised raw JSON payload. * x-www-form-urlencoded payload (key-value pairs). Construct a string by sorting the payload’s key-value pairs in alphabetical order. The pairs must be sorted in alphabetical order with respect to their keys. **Note** * If your webhook contains **query string parameters**, ensure that those key-value pairs are sorted along with the payload’s key-value pairs. * There cannot be any spaces between the key-value pairs. Once you’ve sorted the key-value pairs and constructed the string, append the raw JSON to the end of the string. **Examples** 1\. **Default Payload** Query string parameters’ key-value pairs: ``` subscription\_id=90343, name=basic ``` Default payload/raw JSON: ``` {"created\_date":"2019-03-06","event\_id":"5675"} ``` The constructed string would be: ``` namebasicsubscription\_id90343{"created\_date":"2019-03-06","event\_id":"5675"} ``` 2\. **x-www-form-urlencoded** Query string parameters’ key-value pairs: ``` customer\_name=Brandon, status=active ``` x-www-form-urlencoded payload’s key-value pairs: ``` addon\_description=Monthly addon, quantity=1 ``` The constructed string would be: ``` addon\_descriptionMonthly addoncustomer\_nameBrandonquantity1statusactive ``` **Pro Tip** * If your payload is in the x-www-form-urlencoded format, the entire string must be decoded before generating the hash value. * If one of the key value pairs contains spaces, the spaces must also be included in the constructed string. The hash value can be computed by applying the HMAC-SHA256 algorithm on this string, along with the secret token that was used in Zoho Books. You can then validate the webhook by checking if the hash value computed from your side matches the one in the header (X-Zoho-Webhook-Signature) of the webhook from Zoho Books. You can verify your webhook signature using the following programming languages: **JavaScript:** ```sh const crypto = require('crypto'); function verifyWebhook(queryParams, bodyParams, signature, secretKey) { try { const constructedString = constructString(queryParams, bodyParams); const hmac = crypto.createHmac('sha256', secretKey); hmac.update(constructedString); const calculatedSignature = hmac.digest('base64'); return calculatedSignature === signature; } catch (error) { console.error(error); return false; } } function constructString(queryParams, bodyParams) { // Merge and sort keys const allParams = { ...queryParams, ...bodyParams }; const sortedKeys = Object.keys(allParams).sort(); let result = ''; for (const key of sortedKeys) { result += key + allParams[key]; } return result; } ``` **Java:** ```sh import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.util.Map; import java.util.TreeMap; import java.util.Base64; public class Hmacverify { public static boolean verifyWebhook(Map queryParams, Map bodyParams, String signature, String secretKey) { try { String constructedString = constructString(queryParams, bodyParams); Mac sha256HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256"); sha256HMAC.init(secretKeySpec); byte[] hash = sha256HMAC.doFinal(constructedString.getBytes()); String calculatedSignature = Base64.getEncoder().encodeToString(hash); return calculatedSignature.equals(signature); } catch (Exception e) { e.printStackTrace(); return false; } } private static String constructString(Map queryParams, Map bodyParams) { StringBuilder result = new StringBuilder(); TreeMap sortedParams = new TreeMap<>(queryParams); sortedParams.putAll(bodyParams); for (Map.Entry entry : sortedParams.entrySet()) { result.append(entry.getKey()).append(entry.getValue()); } return result.toString(); } } ``` **Python:** ```sh import hmac import hashlib import base64 def verifyWebhook(queryParams, bodyParams, signature, secretKey): constructedString = constructString(queryParams, bodyParams) calculatedSignature = base64.b64encode(hmac.new(secretKey.encode(), constructedString.encode(), hashlib.sha256).digest()).decode() return calculatedSignature == signature def constructString(queryParams, bodyParams): # Merge and sort query and body parameters allParams = {**queryParams, **bodyParams} sortedParams = sorted(allParams.items()) result = ''.join([key + value for key, value in sortedParams]) return result # Example usage queryParams = {'subscription_id': '90343', 'name': 'basic'} bodyParams = {'created_date': '2019-03-06', 'event_id': '5675'} signature = 'provided-signature' secretKey = 'your-secret-key' verifyWebhook(queryParams, bodyParams, signature, secretKey) ``` * * * ## Configuring SMS Gateways  You can set up webhooks to send and receive message alerts through SMS gateways. All you have to do is configure the SMS gateways using the URL and follow the steps provided below. ### Bulk SMS Bulk SMS is a popular SMS Gateway and is compatible with over 800 mobile network providers, worldwide. **URL: https://bulksms.vsms.net/eapi/submission/send\_sms/2/2.0?username=`%username%`&password=`%password%`&msisdn=${CONTACT.CONTACT\_MOBILE\_PHONE}&message=%message\_content%** To configure the URL for Bulk SMS: * Click the **Gear** icon on the top right and select **Automation**. * Navigate to the **Webhooks** tab and click **\+ New Webhook**. * Copy the above URL into the **URL to notify** field. * Replace the **%username%** and **%password%** placeholders in the URL with the username and password of your Bulk SMS account. * Type your message at the end of the URL, that is, after “**message=**”. * Replace all the blank spaces in your message content by **%20** and all the commas by **%2C**. ![Configure Bulk SMS](/books/help/images/settings/bulk-sms.png) **Note:** If there are other punctuations in your message content, you can check how to replace them with modifiers from [this](https://meyerweb.com/eric/tools/dencoder/) website. However, ensure that you do not replace punctuations that are essential to the message’s syntax. After formatting your message with %20 for blank spaces and %2C for commas, it should look like this: > **URL: https://bulksms.vsms.net/eapi/submission/send\_sms/2/2.0?username=`%username%`&password=`%password%`&msisdn=${CONTACT.CONTACT\_MOBILE\_PHONE}&message=Hello%20${CONTACT.CONTACT\_NAME}.Thank%20you%20for%20the%20purchase%20of%20${INVOICE.INVOICE\_TOTAL}** **Similarly, other SMS gateways can be configured, with only the URL being different.** ### SMS-Magic SMS gateways such as SMS-Magic requires you to enter additional entity parameters to configure the webhook. To configure SMS-Magic: * Enter the URL **https://sms-magic.in/smapi/post** in the **URL** to notify field. * Click **\+ Add Entity Parameter**. * Enter the following text in the parameter field: ![Configure SMS Magic](/books/help/images/settings/sms-magic.png) ``` **User_ID** **%Sender_ID** **%Account_ID** **%hashkey%** ``` Replace the placeholders in the URL with the User ID, Sender ID and Account ID of your SMS-Magic account. The hashkey refers to a standard hashed md5 value of a string that is a concatenation of your User ID, Password, Account ID and Sender ID. **Note:** To generate the hashed md5 value, you can visit [this](https://www.md5hashgenerator.com/) site. ### Text Local Text Local requires an entity parameter and a custom parameter to function. To configure Text Local: ![Configure Text Local](/books/help/images/settings/text-local.png) * Enter the URL **http://api.textlocal.in/send/** in the **URL to notify** field. * Click **\+ Add Custom Parameter**. * Add the **sender** and **apikey** parameter and replace the placeholders in the URL with the relevant information from Text Local. * Click **\+ Add Entity Parameter**. * Give a name for the parameter and select the required conditions from the dropdown menu. Example: numbers = ${CONTACT.CONTACT\_MOBILE\_PHONE} * Select the **Add User Defined Parameters** box and enter the message to be sent along with all the necessary place holders. * Click **Save**. * * * ## Edit Webhooks If you want to update the details of a webhook, you can edit it. Here’s how: * Go to **Settings** on the top right corner of the page. * Select **Workflow Actions** under _Automation_. * In the _Workflow Actions_ pane, select **Webhooks**. * Hover over the webhook you want to edit, click the dropdown to the right, and select **Edit**. * Make the necessary changes and click **Save**. * * * ## Filter Webhooks To filter the webhooks list, follow these steps: * Go to **Settings** on the top right corner of the page. * Select **Workflow Actions** under _Automation_. * In the _Workflow Actions_ pane, select **Webhooks**. * Under Module, select a module from the dropdown for which the webhook was created. Based on your selection, the corresponding webhook will be displayed as a list. ![Filter Webhook](/books/help/images/settings/Automation-FilterWebhook.png) **Note** * You can create only 1 webhook for each workflow rule. * The number of webhooks you can trigger per day varies by your Zoho Books plan. * * * ## Delete Webhooks **Warning:** Deleting a webhook is permanent and cannot be undone. If the webhook is associated with a workflow rule, the workflow rule will not be executed. To delete a webhook: * Go to **Settings** on the top right corner of the page. * Select **Workflow Actions** under _Automation_. * In the _Workflow Actions_ pane, select **Webhooks**. * Hover over the webhook that you want to delete and click the **Delete** icon. ![Click the Delete icon](/books/help/images/settings/webhooks/delete-webhook.png) * In the pop up that appears, click **Yes**. The webhook will be deleted. If you’ve used the webhook in a workflow rule, ensure that you update the workflow rule as the workflow rule might not get triggered. * * * ## Related Topics * [Workflow Rules](/ae/books/help/settings/automation/workflow-rules.html) * [Email Alerts](/ae/books/help/settings/automation/workflow-actions/email-alerts.html) * [Field Updates](/ae/books/help/settings/automation/workflow-actions/field-updates.html) * [In-app Notifications](/ae/books/help/settings/automation/workflow-actions/in-app-notifications.html) * [Functions](/ae/books/help/settings/automation/workflow-actions/functions.html) * [Schedules](/ae/books/help/settings/automation/schedules.html) * [Workflow Logs](/ae/books/help/settings/automation/workflow-logs.html)