Enabling webhooks for the Salesforce Managed App


Our Salesforce managed app has a webhooks feature which enables realtime integration with Amberflo events. This is an inbound realtime feed from Amberflo.

Webhook events update the following Salesforce objects:

  1. Customer
  2. Product items
  3. Pricing plans
  4. Promotions
  5. Customer Prepaid
  6. Prepaid Debits
  7. Invoices

See a list of webhooks here.

Documentation on configuring an outbound webhook using the Amberflo API here.


  1. Prerequisites

The API Key should be configured. See Installing Amberflo.io Salesforce Managed App.

  1. In Setup, type "Sites":
  1. Register a domain if you do not already have one.

For instructions, read here.

  1. Best practice: Create a website for each external package. So in this case, Amberflo.io should have its own website. Click New.
  1. Complete the new site form as follows:

For the Active Site Home Page field, click on the lookup icon, and then search for "InMaintenance". Click on the Name link.

  1. The created webhook site.
  1. Now we need to allow the site permission and access to the Amberflo webhook class. Click on the Site label Amberflo.io.
  1. Click on Public Access Settings, then click on Edit for "Enabled Apex Class Access".
  1. Select AFLO.WebhookRestService and Add to Enabled Apex class, then click Save.

Testing the Webhook

The webhook endpoint is: {{Site URL}}/services/apexrest/AFLO/webhook


So in the above example, the endpoint URL would be:

Ping the endpoint:

curl --location --request GET 'https://amberfloiodemo-dev-ed.my.salesforce-sites.com/amberflo/services/apexrest/AFLO/webhook' \
--header 'Token: xyz' \
--header 'Content-Type: application/json' \


"Welcome to the webhook service!"

Test customer creation:

curl --location --request POST 'https://amberfloiodemo-dev-ed.my.salesforce-sites.com/amberflo/services/apexrest/AFLO/webhook' \
--header 'Token: xyz' \
--header 'Content-Type: application/json' \
--data-raw '[
        "type": "Customer",
        "action": "Created",
        "record": {
            "id": "ABCD",
            "customerId": "ABCD",
            "customerName": "Billow Labs Test",
            "customerEmail": null,
            "enabled": true,
            "createTime": 1661464274941,
            "updateTime": 1661471970868



If the webhook returns the following error, follow the steps 7 and 8 in the Instructions to grant permission.

       "errorCode": "FORBIDDEN",
       "message": "You do not have access to the Apex class named: WebhookRestService"

The status of a webhook call can be viewed in the Amberflo Async Events tab.


Integrating the Salesforce webhook from Amberflo

Once the webhook endpoint is enabled in Salesforce, configure an outbound webhook in Amberflo API to call the Salesforce endpoint. See API Reference.

The following setup calls the Salesforce webhook whenever a customer is created in Amberflo.

curl --location --request POST 'https://app.amberflo.io/webhook' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: api-key' \
--data-raw '{
    "topic": "customer-feed",
    "destinationUrl": "https://amberfloiodemo-dev-ed.my.salesforce-sites.com/amberflo/services/apexrest/AFLO/webhook",
    "authHeader": [
    "transformTemplate": "amberflo-sfdc-app"

Addressing webhook security concerns

  1. A web hook request comes to the Amberflo remote site endpoint.
  2. The request is verified by the rest service AFLO.WebhookRestService by looking to see if the given token is valid.
  3. If the token is invalid, the entire request is rejected.
  4. The token in Salesforce is stored in a custom setting (which only Admins have access to by default).
  5. AFLO.WebhookRestService class then processes the request - per our specific design - and does nothing else. It cannot do anything else.
  6. We do not have to allow any access to the instance though the Guest Site, except through the REST endpoint we created. Essentially there are NO guest users BUT the Salesforce web hook endpoint itself. This is recommended by Salesforce itself.

Additional resources from Salesforce:
Link 1
Link 2

What’s Next