When you receive a webhook call (via Default or Custom API page), the process always creates a new Webhook Entry. This entry is related to a specific webhook definition and contains JSON request payload:
You can process webhooks in a synchronous or asynchronous way, depending on Asynchronous Processing field in webhook settings.
The webhook request JSON is immediately processed by the operation request/response body definition (or by event subscription).
Use this option if you do not care too much about response time and you need to process the call immediately. Note: This it the only valid option, if you need to send custom JSON response.
Webhook request processing is scheduled in Job Queue Entries and will start in a few seconds asynchronously. When receiving the webhook, RESTwithUS will just create new Webhook Entry and answer with HTTP status 200 or 201. The Webhook Entry will be first in Scheduled
Status.
When the job starts, the webhook entry will be processed by the operation request/response body definition or by event subscription, depending on the settings.
Always use this option if the webhook processing can be time-consuming (some services even demand, that the webhook call is answered swiftly). Example: You get the ID of a new order from an external service and during webhook processing you need to get all data of the order and save it in Business Central.
This if the default method of webhook processing, which takes advantage of your usual RESTwithUS setup. If you select your webhook definition from the list, you can open Request Body and Response Body from the menu like in a standard operation:
Let's define a simple Request Body, that will process the webhook JSON. You can map the tables, fields and entities as usual:
If you want to answer the webhook call with specific response JSON, you can define it in Response Body section. Usually this is not needed, webhooks mostly accept an OK HTTP status and do not care about the body (RESTwithUS sends a generic {"Status":"200 OK"}
JSON in such case).
The response works with records loaded during request processing. So for example if you map the request JSON to Customer
01121212
in the request, the response body will use this record for generating the JSON too.
Custom JSON response works with Synchronous processing only – and makes real sense just with Default API Page (HTTP status 201) or Default API Page Function (HTTP status 200) and third-party service processing the response.
For example with Custom API Page Function, Business Central always adds some new nodes and tries to escape the resulting JSON:
If you want to create/update Connections or save some data to Business Central, just make the required updates in table (root
) node Details and operation Details:
For more details see guidelines Importing and Setting up JSON Body Structure and Updating Data in Business Central.
If you call the webhook and process it with Request / Response Body, the call will generate usual Batch Entries:
There are two events in the API WebHook Mgt. RWU codeunit that you can use to process the webhook call with code:
OnAfterNewWebHookRecieved
– this event is fired, when RESTwithUS receives a webhook call and just before a new Webhook Entry is created. Use it to process the webhook call immediately with code.OnBeforeHandleWebHookEntry
– this event is fired just before RESTwithUS processes synchronous or asynchronous webhook entry with the webhook Request and Response definition. Use it to process asynchronous webhook call with code instead.Let's have an example of this event subscription. With this example you will:
Processed
). [EventSubscriber(ObjectType::Codeunit, Codeunit::"API WebHook Mgt. RWU", 'OnAfterNewWebHookRecieved', '', true, true)]
local procedure OnAfterNewWebHookRecievedTestPage(var _APIWebHookEntryRWU: Record "API WebHook Entry RWU";var _WebhookProcessed : Boolean)
var
APIEndpointRWU: Record "API Endpoint RWU";
APIScriptRWU: Codeunit "API Script RWU";
ProviderID: Enum "Provider ID RWU";
WebhookID: Enum "WebHook ID RWU";
JSONData: JsonToken;
JToken: JsonToken;
begin
//Get the webhook endpoint - see if you should process the subscription
APIEndpointRWU := APIScriptRWU.GET_WEBHOOK_RECORD(ProviderID::TestProvider,WebhookID::"Test Custom API Page");
if _APIWebHookEntryRWU."Endpoint Id" <> APIEndpointRWU.ID then
exit;
//Do something with the JSON data
JSONData.ReadFrom(_APIWebHookEntryRWU.GetPayload());
//... process the JSON data
//Generate specific JSON body response and save it into the webhook entry
_APIWebHookEntryRWU.SetResponsePayload('{"status":"Processed by event"}');
//Mark the webhook entry as processed
_WebhookProcessed := true;
end;
Tip: You can use
SetResponsePayload
function to save some information into Webhook Entry record (e.g. as a log). In some cases it will be returned in the response JSON body too, but please be aware, that Business Central API always adds some extra data here and sometimes tries to escape the resulting JSON:
{
"@odata.context": "http://restwithus-19:7048/BC/api/rwuCore/rwuTest/v1.0/$metadata#Edm.String",
"value": "{\"status\":\"Processed by event\"}"
}
Let's have an example of this event subscription. With this example you will:
Processed
). [EventSubscriber(ObjectType::Codeunit, Codeunit::"API WebHook Mgt. RWU", 'OnBeforeHandleWebHookEntry', '', true, true)]
local procedure OnBeforeHandleWebHookEntryTestFunction(var _APIWebHookEntryRWU: Record "API WebHook Entry RWU";var _WebhookProcessed : Boolean)
var
APIEndpointRWU: Record "API Endpoint RWU";
Customer: Record Customer;
APIScriptRWU: Codeunit "API Script RWU";
ProviderID: Enum "Provider ID RWU";
WebhookID: Enum "WebHook ID RWU";
JSONData: JsonToken;
JToken: JsonToken;
begin
//Get the webhook endpoint - see if you should process the subscription
APIEndpointRWU := APIScriptRWU.GET_WEBHOOK_RECORD(ProviderID::TestProvider,WebhookID::"Test Custom API Page Function");
if _APIWebHookEntryRWU."Endpoint Id" <> APIEndpointRWU.ID then
exit;
//Process the data, e.g. save them to Customer manually
JSONData.ReadFrom(_APIWebHookEntryRWU.GetPayload());
JSONData.SelectToken('$.no',JToken);
Customer.Get(JToken.AsValue().AsText());
JSONData.SelectToken('$.name',JToken);
Customer.Name := JToken.AsValue().AsText();
Customer.Modify(true);
//Save some data into webhook entry response (e.g. for logging purposes)
_APIWebHookEntryRWU.SetResponsePayload('{"status":"Processed by event"}');
_APIWebHookEntryRWU.Modify(true);
//Mark the webhook as processed, so it won't be processed again by the endpoint Request and Response body
_WebhookProcessed := true;
end;
Tip: Use this event to process time-consuming asynchronous webhook calls. When processing the data, you may for example need to load the webshop order data from an external service API – such kind of operation should never be done during the initial webhook processing.