Bulk Webhooks on Flow with Kentaa

Kentaa is a digital fundraising platform for teams and individuals. This guide shows how to replicate Team, Actor and Donation records on Salesforce using Flow and Webhooks.




Scenario - Team Creation on Kentaa

Creating a Team fires the same "Team Created" event for all team members - this causes a race condition during the related Salesforce Account inserts.

This guide shows how to mitigate the issue by introducing a second "Platform Event-triggered" flow in addition to the standard webhook flow.


Key Concepts


Flow 1:


Flow 2:





Part 1 - Webhook Flow:

Kentaa Configuration:

Kentaa support provisions a customised environment with a suitable hierarchy and provides an API key to support callbacks. For this demo, we use the following configuration: Site ➝ Team Fund Raiser




A Kentaa Donation corresponds to a Salesforce Task.



Fund Raising Actor ("Action")

Individual fundraising Actors in Kentaa are known as "Actions" and are represented as Contacts in Salesforce. Donations associated with Actors correspond to Salesforce Tasks with the the WhoId pointing to the corresponding Contact




Two or more fund raising Actors may form a Team. A Kentaa Team is modelled as a Salesforce Account with team Actors represented as related Contacts. Donations associated with a Team are modelled as Salesforce Tasks, with the WhatId pointing to the Account and the WhoId pointing to the Contact.



Create the necessary Kentaa External IDs to implement the model:


Salesforce External Ids:



Modify the Account object with an External Id representing the Kentaa Team Id and grant access to this field for all profiles.


Modify the Contact object with an External Id representing the Kentaa Actor Id and grant access to this field for all profiles.


Kentaa Team Creation:

When the Save button is clicked on the Kentaa platform, a Team event for every team member is sent to Salesforce. This causes a race condition - multiple webhooks triggered at the same time all assume the absence of the Team / Account record.


Salesforce Account Creation:

To avoid the race condition, we utilise Platform Events to convert parallel webhook processing of Kentaa's event notifications into event collections that are processed sequentially in a later context. A second flow retrieves each Kentaa notification from the event queue for processing.

In this second Flow, Streamscript processes the queue in batches as ordered platform event collections and the effects thereof are committed to the database



Create a Platform Event to enable deferred processing of Kentaa notifications:


Kentaa Event Message Structure:

    "object_type": "action",
    "object_id": 42,
    "event_type": "counters.update",
    "application": "Kentaa",
    "site_id": 12


Salesforce Platform Event Definition:

The Platform Event has a single Text Area field, Data__c capped at 131,072 bytes. This size will always accommodate the full Kenta Notification.




Kentaa - Callback:

To retrieve the full event detail, the recipient of the webhook is expected to call back to Kentaa using a combination of the object_type and object_Id as the retrieval key. Notification detail retrieval is covered in the Subscriber Flow below.


Salesforce - Named Credential:


Create a Named Credential to hold your API key. At runtime, the named credential resolves the URL to the configured Kentaa physical endpoint. It also securely manages authentication for an external service callout on behalf of the authorized user performing the callout.


Salesforce - External Services:

Create three external services to support the Team, Actor and Donation callouts

Navigate to Setup > External Services



For each service, repeat the following steps:

1. Select the "From API Specification"


2. Complete the registration details for each service:





3. Click Save & Next



4. Check the available Get operation



5. Click Finish



You should now have three external services available for use in the Subscriber flow:



With setup complete, proceed to creating the Webhook flow and Subscriber flow:



Part 1 - Webhook Flow:

Webhook notifications sent from Kentaa trigger the Kentaa Webhook flow. The Webhook action extracts the notification JSON and populates Data__c field of the Kentaa_Webhook__e platform event - parallel notifications are effectively batched and sequentialised - parallel notifications are effectively batched and sequentialised. This approach is the first of a two part strategy to address the issue of processing concurrent related requests.



Step 1 - Convert the parallel webhook to a batched sequential event:

# Streamscript
$Webhook.response  = '200 - OK'
$Kentaa_Webhook__e = New-Kentaa_Webhook__e
$Kentaa_Webhook__e.Body__c = $Webhook.request

return $Kentaa_Webhook__e 

The script returns a custom Platform Event that holds the event notification JSON.


Step 2 - Add a step to save the data, thereby publishing the platform event


Step 3 - Save the Flow:

Note (This flow property ensures the Site Guest User can insert the task record)



Part 2 - Subscriber Flow:

The Subscriber Flow makes use of the Bulk directive in an initial Streamscript step - this directive provides a comprehensive view of potentially related inbound events that would not be possible had these events been separately processed in multiple webhook flow instances.

# Streamscript Bulk

This Streamscript step categorises each Kentaa notification in the batch by qualifying type — new donations (Tasks), team members (Contacts), or teams (Accounts) — all other notifications are flagged. Duplicate team notifications are also flagged to prevent race conditions during record insertion or updates.



The Decision step routes the filtered notifications. Flagged messages not pertinent to the process are directed to the 'skipped' path while relevant de-duped Team, Actor, and Donation messages move forward for further processing. Each path concludes by executing an update or insert in Salesforce


Create a new Platform Triggered flow


Go to Setup > Flows > Platform Event - Triggered Flow. This flow will subscribes to platform event collections published by the webhook flow described above.




Select the platform event type Kentaa Webhook.


Click Save and ignore any warnings.


Step 1 - Add filter step

Add a Streamscript step as the first step in the flow


Modify the existing '#Streamscript' language instruction at the start of the script with the the Bulk directive

# Streamscript Bulk


Step 2 - Add filter logic

The script eliminates redundant 'Team created' eventsand excludes events that are not relevant to the process.

Paste in the following script:

# Streamscript Bulk
$ids         = []
$types       = []
$uniqueKeys  = []

$items = {!$Record}
foreach ($item in $items) {
    # read the webhook body
    $o = Json-Decode $item.Data__c
    # filter
    $id     = $o.object_id                     # eg: 12345
    $type   = `$o.object_type|$o.event_type`   # eg: team|sign_ups.create
    $key    = `$type|$id`                      # eg: team|sign_ups.create|12345
    # de-duplicate ( duplicates assigned 'null' )
    if ($uniqueKeys.contains($key)) {
        $id = null;  $type = null

    # add 'null - normalised' items
# $ids and $types are correlated  - that is, $ids[1] relates to $types[1], etc
#   - $types: resolves to decision step path - team, participant, donation
#   - $ids: via external service callout retrieves fully described event for $id
return  -num $ids -text $types    


Click Done




Step 3 - Add a Decision element:

The Decision step routes notifications from the Filter Step — Team, Actor, and Donation messages move forward for further processing while all other messages are directed to the Skip path per the table below.:

object_type event_type   value   outcome
team sign_ups.create team|sign_ups.create Team
action sign_ups.create action|sign_ups.create Actor
donation sign_ups.create donation|sign_ups.create Donation
donation donations.update donation|donations.update Donation
null null <default> Skip




Outcome - Team



Outcome - Actor



Outcome - Donation




Complete the Team Path:

Update the relevent Account record in the database or insert a new one if necessary.



Step 4 - Under the Team path, add an Action element. Then select TeamService to complete the Team callout.




Step 5 - Add a Get Records element that represents the Account



Step 6 - Add a New Assignment element. Assign the Kentaa Team Id and Kentaa Team Name using the response from the Kentaa Team callout


Step 7 - Add a New Decision element. Test for an empty Id on the selected Account record.


Default: (null value)


Step 8 - 'Upsert' the Account

Under the Account Exists path, add an Update Records step

Under the Not Exists path add a Create Records step


Complete the Actor path:

Link the Contact (Actor) with the corresponding Account (Team) - then upsert the Contact record.



Step 9 - Under the Actor path, add an Action element. Then select ActorService to complete the Actor callout.



Step 10 - Add a Get Records element that represents the Account.


Step 11 - Add a Get Records element that represents the Contact.


Step 12 - Add a New Assignment element that hydrates the selected Contact record.

Set Variables:


Step 13 - Add a New Decision element. Test for an empty Id on the selected Contact record.


Default: (null value)


Step 14 - 'Upsert' the Contact

Under the Contact Exists path, add an Update Records step

Under the Not Exists path add a Create Records step


Complete the Donation path:

Insert a Task representing the Donation. Before inserting, resolve the Donation's Team ID to its corresponding Salesforce Account ID and the Donation's Actor ID to its corresponding Salesforce Contact ID. Then, map the WhatId on the Task to the resolved Contact ID and the WhoId on the Task to the resolved Account ID.



Step 15 - Under the Donation path, add an Action element. Then select DonationService to complete the Donation callout.



Now complete the Donation path



Step 17 - Add a Get Records element that represents the Account.


Step 18 - Add a Get Records element that represents the Contact.


Step 19 - Insert the Task with a Create Records step

Set Field Values for the Task


The completed flow should look like this:




Part 3 - Test the Integration:

Navigate to your the site page provisioned by the Kentaa team, in our case "Test". Click Continue



Select Team, then click Continue



Add the team leader ("Jake") and additional team member ("Lilly") and the Team ("Jakes Rakes")




Finally, make a donation under Jakes name via the simulated payment gateway.



Click Submit. Kentaa sends a number of webhooks to Salesforce. Our integration correctly creates:



Wrap Up:

This integration employed Streamscript and platform events to resolve concurrency issues presented in the scenario at the start of this guide. These integration techniques can be adapted to other Salesforce webhook scenarios with similar dependencies..



Getting started with Streamscript
Install from the Salesforce AppExchange
Package install link: /packaging/installPackage.apexp?p0=04tGA000005BsIL