💃 Webhooking your Salesforce Org 🕺

Building a Secure Webhook Receiver on Salesforce Sites

Good morning, Salesforce Nerds! Ever get a request like this? 👇️ 

"Hey, we just need to send new order info into Salesforce when customers check out. Super simple. Just a webhook."

Ah yes, the phrase that launched a thousand panic deployments.

But fear not, architect friend. ❤️ 

Today we’re walking through how to build a secure, scalable, and cheekily clever webhook handler on Salesforce using Sites, HMAC verification, and good ol’ Apex.

This one’s for the architects and senior devs who know that a webhook is never just a webhook. 😅 

TABLE OF CONTENTS

JUST A WEBHOOK, THEY SAID. IT’LL BE EASY, THEY SAID.

WHAT ARE WE BUILDING?

Picture this: your external order system wants to POST a JSON payload to Salesforce every time a new order is placed. 🤔 

But, the wrinkle … it’s not capable of OAuth’ing into the org. It needs a public endpoint.

What now?

Believe or not, Salesforce isn’t leaving you dead in the water in this scenario. 🛟 

Let’s see how. The goal is to:

📥️ Receive those requests through a public endpoint

🔎 Verify the payload using an HMAC signature

⚙️ Validate & process the data

⬅️ Respond with a proper HTTP status

✍️ Log failures without melting down

We can do this all with Salesforce Sites and the Guest User, one of the more misunderstood (and sometimes feared) personas in the Salesforce universe. 🌌 

POWERFUL, PUBLIC, AND SLIGHTLY TERRIFYING

WHY SALESFORCE SITES?

Salesforce Sites let you expose Apex controllers to the public internet without authentication. 😱 

This makes them perfect for:

🪝 Inbound webhook handling

👈️ Status callbacks from payment providers

📤️ Public form submissions

🔗 Integration touchpoints with systems that don’t speak OAuth

But they also come with landmines - like guest user permissions, rate limiting, and security risks - so it’s up to us to play it smart.

EVERYTHING YOU NEED - MINUS THE EMOTIONAL SUPPORT

KEY COMPONENTS

Let’s break this down like a good consultant would on a whiteboard (but with more caffeine and fewer marker fumes):

1. The Site & Guest User

  • Create a Salesforce Site with an Active Site Home Page pointing to a simple Visualforce page (even if you never use it).

  • Assign a Guest User Profile with access to the Apex class and only the required object permissions (e.g., read access to a Product__c, create access to Order__c).

  • IP Whitelist the order system’s outbound IP range at the org level.

  • Disable unnecessary features on the Site like Search, ReCaptcha, etc.. 🚫 

2. The Apex Controller

Use a @RestResource class to receive the inbound request. 📞 

Example skeleton:

@RestResource(urlMapping='/order-webhook')
global with sharing class OrderWebhookController {
    @HttpPost
    global static void handleOrder() {
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;

        // 1. Validate headers
        String signature = req.headers.get('X-Signature');
        String secret = 'SuperSecretKey123'; // Externalized via Custom Metadata in real life

        // 2. Verify HMAC
        if (!verifySignature(req.requestBody.toString(), signature, secret)) {
            res.statusCode = 401;
            res.responseBody = Blob.valueOf('Invalid signature');
            return;
        }

        // 3. Process payload
        try {
            OrderPayload payload = (OrderPayload) JSON.deserialize(req.requestBody.toString(), OrderPayload.class);
            createOrder(payload);
            res.statusCode = 200;
            res.responseBody = Blob.valueOf('Order received');
        } catch (Exception ex) {
            logFailure(req.requestBody.toString(), ex.getMessage());
            res.statusCode = 500;
            res.responseBody = Blob.valueOf('Error processing order');
        }
    }

    private static Boolean verifySignature(String body, String signature, String secret) {
        Blob mac = Crypto.generateMac('HmacSHA256', Blob.valueOf(body), Blob.valueOf(secret));
        String expectedSig = EncodingUtil.convertToHex(mac);
        return Crypto.isValidMac(Blob.valueOf(body), Blob.valueOf(secret), EncodingUtil.convertFromHex(signature));
    }
}

🔒️ Pro Tip: The verifySignature() function prevents anyone with the endpoint from spoofing requests.

HMAC ensures only payloads generated with your known secret are processed.

3. Logging Failures

Don't let bad requests disappear into the abyss.  

Use a custom object like Webhook_Event__c to log things like:

  • Raw payload

  • Status

  • Error message (if any)

  • Timestamp

Then, later, build a screen flow or dashboard to monitor these and investigate patterns. 👍️ 

For now, we’re just logging - no retries, no queues - but tell your future self to explore:

  • Platform Events for async processing

  • Queues or Batching for retries

  • Custom Notifications for alerts

4. Rate Limiting & Governance

You’re probably thinking: “This Guest User is living dangerously.”

Lock it down:

  • Assign only the bare minimum CRUD permissions

  • Use Field-Level Security religiously

  • Consider a Named Credential–based pattern if you need authenticated callbacks in future

  • Monitor usage via Event Monitoring or External Services Logs

If your endpoint gets hammered, you don’t want it taking down your org’s API capacity.

SURVIVAL TIPS FROM THE WEBHOOK WILD WEST

LESSONS FROM THE FIELD

You don’t truly know a webhook until it breaks at 2:00 AM and you’re debugging it in your pajamas with a bowl of cereal.

Here are a few hard-earned lessons from the trenches to help you avoid becoming that person. 👇️ 

 Always test with a tool like Postman to simulate signature headers and payloads

🧠 Don’t forget to check the Site's CORS settings if dealing with JavaScript-based clients

😄 Use Custom Metadata for your shared secret key - not hardcoded strings

💂 Treat every Guest User endpoint like a VIP door to your org. Guard it like one.

WRAPPING IT UP

FINAL THOUGHTS

Webhooks are deceptively simple until they aren’t.

The good news is Salesforce gives us all the tools - Sites, Apex, Crypto class, and logging - to build a secure, scalable webhook handler that won’t wake you up at 2am.

Sure, it’s not as trendy as a real-time streaming microservice architecture with Kafka and Kubernetes.

But you know what?

It works. It scales. And it keeps your order data flowing.

Happy Coding!

SOUL FOOD

Today’s Principle

"Passwords are like underwear: don’t let people see it, change it very often, and you shouldn’t share it with strangers."

Chris Pirillo

and now....Salesforce Memes

What did you think about today's newsletter?

Login or Subscribe to participate in polls.