Creatio’s webhook service will technically accept every webhook you throw at it, regardless of whether the formatting matches the existing process structure. Processing, however, is very particular about format. Many times, you will receive webhooks from a source with no control over payload structure. Some customers turn to middleware tools to reformat the payload, however, you can create some psuedo-ETL (extract-transform-load) business processes in Creatio using OOTB tools to manage your payloads as well. To do this, you can create your own processes to handle the incoming webhook records, based on the OOTB webhook business processes. This guide is not intended to be an exhaustive solution, but merely an intro to the OOTB webhook components and how you can use some creativity in combination with Creatio’s business processes to work around your payload structure difficulties. This guide is also intended to be a foundation. I encourage you to expand, grow, and add your own scale/complexity as needed.
First, you should note the key processes of webhook consumption in Creatio. I assume you already have webhooks configured, and if not, that is already well documented, so I won’t get into that piece here.
- Start process to create object records based on incoming webhooks
This is the first business process used to process the incoming webhooks. The OOTB business process runs on a timed trigger with a 1 minute interval. This process immediately calls the following via subprocess and nothing more. This first process is simply a trigger. (Arguably, redundant, as you could’ve just started your 1min trigger on #2 below, which I will recommend later when we build our custom replacements.)
- Engagement tools App: Start process to create object records based on incoming webhooks
The name above is an alternative version that appears in new versions of Creatio. If you have the Engagement App version, then you will likely have BOTH versions available with one disabled. The Engagement App version includes an additional subprocess: Define contact based on submitted form.
For simplicity, we will ignore this flow for now. I’ll address this at the end, as there’s many ways to incorporate the find/create contact processes.

- Create object records based on incoming webhooks
This is where the magic happens. This process reads all webhooks that are in a “New” status, indicating they need to be processed. To process the webhooks, Creatio calls a user task “Webhook To Entity UT”, which translates the incoming JSON payload to the appropriate objects and fields identified. This assumes you’ve strictly followed the Creatio webhook format – and if not, then your webhook stalls here and fails to process. This user task handles every part of webhook processing, from identifying the appropriate object, the fields, and the status of the incoming webhook record/payload itself.

We will disable both business processes above and create our own to handle our custom logic.
Start with a stable foundation.
The second process of Creatio’s webhook pair is the one with all the juice. We can simplify and combine these two as mentioned previously. Likewise, we want to keep Creatio’s OOTB webhook processing in place, so we’ll start with a copy of process number 2.
- Open the process “Create object records based on incoming webhooks”
- Select Actions -> Copy Diagram
- Save this new process with a new title and code as desired. Otherwise, you can also just use a “Custom - ” or “Usr” prefix – whatever is relevant for your environment. Be sure to set your package appropriately as well.

The customization.
Now that we have our foundation, we can start to make the necessary adjustments.
-
The trigger
This process starts with a manual trigger. We have two options here: timer or trigger.
- Trigger
My personal preference in all scenarios is to convert these to a trigger. Not only will this help to keep your logs from bloating with processes that run every 1 min doing nothing, but this will also simplify our processing for ETL, as we need to read the incoming payload to determine how to route the record through our new process. For a trigger, set the object to Webhook and event to “Record added”. For added security, we’ll set a condition on this for “Status = New” as well.

- Timer
If you regularly receive a very high volume of webhooks (several per minute, constantly, throughout the day), then stick with the 1 min interval. For most, running 1 min timers on batch is overkill. Likewise, this will complicate our ETL process as we would have to add an additional read collection element with our new criteria, alongside another subprocess to manage the collection of incoming records. I’ve documented this for reference, but we will not be using timer for this guide.

-
Webhook read
The OOTB process, built for handling webhooks in batch, uses a “Read collection” element. The OOTB user task “Webhook to Entity UT” expects a collection for input. For simplicity, we’re going to keep this node but simply move to later in the process. We’ll also need to read the newly triggered record as well.
- Copy the “Read collection”, paste this just after the trigger, then update this element to “Read the first record in the selection”
- Set the label to “Read new webhook”
- Update the filter to read the incoming trigger Id

- Conditional evaluation
The ‘OR’ element currently evaluates for webhooks “yes or no”. Since we moved to a trigger, this is always yes. However, we want to sort based on OOTB behavior vs. our custom behavior. We’ll keep the OR element but update the label and conditions. Since we are reading each record independently, we can analyze in incoming request body to determine whether the format matches Creatio’s suggested format OR some other format. Creatio’s payloads always start with {"EntityName": which we will leverage in our conditional evaluation.
- Change the “Conditional flow” evaluation from the existing “Count” logic to our new behavior determining whether or not the payload is an OOTB Creatio format or something else:
[#Read new webhook.First item of resulting collection.Request body#].StartsWith("{\"EntityName\"")
- The NO path is where we will begin to integrate our custom logic for our new ETL process.
- ETL process
You can use strictly a process alone to manage the webhook behavior, without any additional objects/tables, though this tends to get messy and requires a lot of C# formula steps and substrings. However, if your source is completely inflexible then you may need to go on this route. This does get a bit messy and is inherently sensitive to incoming data format as we’re doing simple string manipulation/extraction but can be reliable assuming the data structure remains the same. Likewise, if your incoming data structure were to change for whatever reason, you’d likely still have an issue importing your payload regardless of method of extraction.
In some instances, you might even be able to create the entire Creatio structure as desired, but perhaps there are some additional field wrappers preventing direct ingestion. This step will require you to conduct your own analysis, development, and testing for your unique incoming payload.
In this example, I’m assuming that I have an incoming lead from a web form, so I want to grab a few key data points like first and last name, phone, email. I might also have information like interested products, notes, as well. Alternatively, this webform might be uniquely specific to a certain product, like a Mortgage. In that case, even though the payload may not have the info, I can still set those values in the process.
- Create a new subprocess that will manage the logic for our unique payload format.
- Create a new input parameter for “Request body” so that we can pass this in from the parent record.
- Define the fields we want to extract from the request body by creating a “parameter” for each field.
- Set the value of each parameter to a C# string formula to extract the desired values. You will need to adjust this based on your use case. I’ve included an example payload and formula string for reference:
- [#Request body#].Substring(([#Request body#].IndexOf("\"name\":\"") + 8), ([#Request body#].IndexOf("\"", ([#Request body#].IndexOf("\"name\":\"") + 8)) - ([#Request body#].IndexOf("\"name\":\"") + 8)))
- You can use this formula, adjusting the field name and offsets for the desired incoming fields. Name, consisting of 4 characters, plus 4 from 3 quotations and a colon. First name, by contrast, is 10 characters, plus the four from quotations and the colon. Be sure to account for any other characters or spaces when constructing your Substring formula.
- [#Request body#].Substring(([#Request body#].IndexOf("\"First Name\":\"") + 14), ([#Request body#].IndexOf("\"", ([#Request body#].IndexOf("\"First Name\":\"") + 14)) - ([#Request body#].IndexOf("\"First Name\":\"") + 14)))


- Now that we’ve defined our field values in the parameter formulas, we can drop in an “Add data” node, setting the fields as desired. In this case, we’re going to create a new Lead record, using a few of the relevant fields from our payload: Name (as lead name), first name, last name, and phone (which we will map to email as this appears to have been repurposed on the web form based on incoming data). This part is nice and simple – drop the node, select the Lead object, add the relevant fields, then map each of those to the parameters we created.

- With this process completed / saved, move back to our “parent” process with the trigger and add this as a subprocess. Set the “Request body” parameter to the value of the “Read new webhook” element’s “Request body”.


- Now that we’ve processed our payload, we need to update the status of the webhook appropriately. To do so, we’ll add a new node after the subprocess to set the webhook record’s status to “done”.

- Finally, we need to make sure to update the status of failed webhooks in our “default path”. Since we’re adding logic to conditionally skip the OOTB Webhook user task, we want to include some redundancy of our own. In this case, we failed to register the webhook as an OOTB payload, we failed to match our condition for the lead subprocess, so we need to set the status to “Failed.”

Extra credit – find / create contact records
Remember my mention of the “Engagement App” version of the process? That version includes some additional logic for tracking UTM information. This can be helpful depending on your implementation. Likely, a Marketing customer will want to track this info. If so, I suggest getting familiar with that subprocess and incorporating this into your new custom webhook processor. Even if you’re not a Marketing user, there’s another subprocess buried in these subprocesses that is beneficial for everyone: Searching and creating contact.
This process allows for input parameters for common contact information data points, then will identify a matching contact based on the determined logic, returning the contact Id for matched existing contact records or will create a new contact record based on the searched values. Most likely, you will want this. You’ll get better insights to leads that you’ve had prior interactions with, establish history with new contacts, and generally just improve your data quality. Adding this to our subprocess is quite simple.
- Return to our ETL subprocess, then add a new “Subprocess” node, selecting the “Searching and creating contact” process from the list.
- Define our input parameters on this node, allowing the subprocess to find/create the contact as appropriate.
- Update the “Add data” node. Now that we are working with Contact records, rather than string fields, we can simply pass the Id from the find/create subprocess, as this will have the contact info we provided. As such, you can remove the name/phone/email fields from the Lead record, as that would be redundant alongside the contact record.

Final cleanup
Be sure to disable the old webhook processes…
- Start process to create object records based on incoming webhooks
- Engagement tools App: Start process to create object records based on incoming webhooks
…and enable our new processes
- Custom - Create object records based on incoming webhooks
- Custom - Webhook - New lead from website