When integrating external applications with Dynamics 365 Business Central, one of the classical way is to use APIs (standard or custom APIs) and then call the relative endpoints from the external application.
As said in the past, exposing entities by using standard or custom API pages is the recommended way for doing integrations with Dynamics 365 Business Central. By using APIs, the schema of your integration is the following:
Here, an external application calls a Dynamics 365 Business Central API endpoint by using simple HTTP methods and then it receives a JSON response from the ERP.
One of the problem that you can have when integrating external systems is that sometimes the external application needs to react to changes that occours on ERP entities. Imagine for example to have an external application that needs to handle an external processing (for example shipments labels printing) for every sales order that comes from Dynamics 365 Business Central. Instead of pulling the ERP for retrieving orders and their modifications on some scheduled timing (for example every N minutes), could be useful if the ERP notifies directly the external application every time an entity changes.
This is exactly the concept of Webhooks: Webhooks is the way to get notified if an entity changes in Dynamics 365 Business Central:
In Dynamics 365 Business Central, every entity exposed as API supports webhooks natively.
To start working with Webhooks, you need to follow a request/response workflow in order to establish the communication:
To show how you can work with Webhooks in Dynamics 365 Business Central, imagine that we have an external system that needs to be notified on every changes that occours on a Sales Order record in Dynamics 365 Business Central.
I’ve deployed on my Azure subscription an Azure Function that receives a JSON body (notification from Dynamics 365 Business Central with the details of the modified entity) and then performs some work as needed by our business scenario. When deployed, the Azure Function has a public URL (endpoint) and this is the notification url that we’ll use when establishing the webhook subscription to the Sales Order entity in our ERP.
NOTE 1: in our calls here we’re using Basic authentication, but you can use also OAuth2 and in this case the TENANTID parameter is not needed.
NOTE 2: In the samples provided I’m connected to my main production environment (called Production) but you can change this name accordingly with the name of the Dynamics 365 Business Central environment you want to use.
As a first step, we call the Dynamics 365 Business Central Subscriptions API in order to check if there are active webhooks subscriptions on our tenant. For this, we need to send a GET http request to the following endpoint:
and the response from the tenant is as follows:
The response is a JSON array of the active webhook subscriptions and in this case it’s empty (no subscriptions established).
To register a webhook subscription, we need to send a POST request to the following endpoint, with Content-Type = application/json:
When the POST request is issued to the subscription API, Dynamics 365 Business Central sends a request to the notificationUrl endpoint by passing a validationToken parameter in the query string.
The subscriber (in my case my Azure Function) retrieves this token from the query string and then it sends back to the caller (Dynamics 365 Business Central) a response with a body that contains the validationToken and by setting http status code = 200 (success).
When Dynamics 365 Business Central receives the response, it checks for the validationToken and if all is ok the subscription is established.
and if I check the detail of the caller (Azure Application Insights is an extremely useful tool for that), I can see that the caller is an application that comes from North Holland (datacenter location of my Dynamics 365 Business Central tenant):
P.S. this is a nice way for knowing the exact location of the datacenter region where your Dynamics 365 Business Central tenant runs.
What happens now that my webhook subscription is activated? Dynamics 365 Business Central starts sending notifications to my endpoint every time something happens on the subscribed entities (pushing).
Here we’ve subscribed for receiving notifications about Sales Orders. If I modify a Sales Order in Dynamics 365 Business Central, a notification is sent to my Azure Function (notificationUrl parameter).
This is what you can see from the Azure Portal after modifying something on a Sales Order record:
As you can see from the Azure Function monitor (Server requests diagram), a new HTTP request is arrived to my endpoint:
and if you inspect the incoming request details, you can see that the caller is always a cloud application that comes from the same region as above mentioned (my Dynamics 365 Business Central tenant).
To show the incoming body request (notification details sent from Dynamics 365 Business Central to my Azure Function) I have logged the incoming request body in the Azure Function log. As you can see in the picture below, it contains a JSON with the modified entity (resource url) and its related state change (created, updated, deleted):
Wow… Dynamics 365 Business Central has sent you a notification!
Please always remember that:
Webhooks subscriptions expires in 3 days (default value). They can be renewed by sending a PATCH request to the subscriptions API (as in the following URL) with Content-Type = application/json:
This is not well documented by Microsoft actually and it’s a source of problems, but remember that in order to successfully renew a webhook subscription, you need to retrieve the @odata.etag value from the response received when you have established the subscription (see above) and then pass this value as a If-Match block in the PATCH request header.
Without this, you will receive an error that says “Could not validate the client concurrency token required by the service. Please provide a valid token in the client request.”.
Remember also that the @odata.etag value must be passed unescaped (so change \” to “) otherwise you will receive an error saying that “Request data is invalid” (HTTP 400 Bad Request error).
Renewing a subscription also updates the @odata.etag value, so be aware of this (you need to save the new value after the renewal).
NOTE for the on-premise version: the duration for a subscription is 3 days as default also for the on-premise version. This value is specified in the CustomSettings.config file under the ApiSubscriptionExpiration entry. In this file there is also a maximum number of subscriptions admitted specified in the ApiSubscriptionMaxNumberOfSubscriptions entry.
To delete a webhook subscription, you can send a DELETE http request to the following endpoint:
Also this is actually not well documented by Microsoft, but to successfully delete a webhook subscription you need to do exactly like the renewing process previously described (If-Match header with the @odata.etag value).
To have a list of all the webhooks supported entities, you can send a GET request to the webhookSupportedResources endpoint (please be aware of the endpoint url):
Here you can see all your standard and custom entities exposed as APIs.
As you can see, Webhooks are extremely powerful and permits you to have a “push-based solution”, where is the ERP that calls you when something happens.
From the external application, in order to have a complete workflow always running by code (no human interaction) you need to: