Article
Build a GTM Chaos Harness: Mocking CRM Webhooks with Claude Code
Most GTM operators treat the CRM sandbox as the ultimate proving ground. The logic is simple: if the webhook fires in the sandbox and the automation picks it up, it’s ready for production.
But sandboxes are deceptive. They are quiet, predictable, and remarkably polite. They don't usually hit you with 429 rate limits. They rarely suffer from 10-second network jitters. They don't simulate the specific architectural failures—like signature expiry or batch timeouts—that bring down production lead-routing pipelines.
Testing against a live sandbox only proves the "happy path" works. To build resilient GTM systems, we need to test the plumbing when it leaks. We need a chaos harness.
Using Claude Code, we can scaffold a local CRM mock server in minutes. This allows us to simulate HubSpot signature failures, Salesforce SOAP batching errors, and malformed payloads before a single byte of data touches our production middleware.
Why Sandboxes Fail the Stress Test
Sandboxes are designed for functional verification: Does Field A map to Field B? They are not built for performance or resilience testing.
Consider HubSpot’s v3 signature verification. It requires your server to validate a hash of the request method, URI, raw body, and a timestamp. HubSpot enforces a strict 5-minute replay window. In a sandbox, you set this up once and it works. In production, clock drift on a server or a delay in a proxy layer can cause your ingestion to reject perfectly valid leads. If your code isn't tested against a "late" payload, your logs will just show a wall of 401 Unauthorized errors while sales reps wonder why the queue is empty.
Salesforce Outbound Messaging presents a different challenge. It uses SOAP-based "at-least-once" delivery, batching up to 100 records per payload. If your endpoint acknowledges the first 99 records but fails on the 100th, Salesforce will retry the entire batch for up to 24 hours. Without a way to simulate partial failure or high-latency acknowledgments, you are just guessing how your system will react to a retry loop.
Scaffolding the Harness with Claude Code
We want a local Node.js server that can toggle between "Healthy CRM" and "Chaotic CRM." Using Claude Code, we can initialize this interactively.
Instead of writing a massive boilerplate script, I use Claude to generate the core Express structure and then layer in the specific CRM logic.
The Prompt Strategy:
- Initialize: "Create a Node.js Express server that listens for webhooks on
/webhooks/hubspotand/webhooks/salesforce." - Schema Generation: "Generate a HubSpot v3 Contact creation payload and a Salesforce Outbound Message SOAP envelope based on standard schemas."
- Authentication Logic: "Add a utility that generates valid
X-HubSpot-Signature-v3headers using a dummy client secret."
Simulating HubSpot v3 Failures
HubSpot’s v3 authentication is more robust than old API keys, but more prone to configuration drift. It requires an HMAC-SHA256 hash of a concatenated string: Method + URI + Body + Timestamp.
In our mock server, we instruct Claude Code to create a HubSpotGenerator class with a chaos toggle.
- Signature Drift: The server sends a payload where the signature is calculated with an incorrect secret. This tests if your middleware correctly returns a 401.
- Replay Attacks: The server sends a
X-HubSpot-Request-Timestampfrom 301 seconds ago. This verifies your ingestion logic respects the 5-minute security window.
Breaking the Salesforce SOAP Loop
Salesforce expects a very specific XML response: <Ack>true</Ack>. If it doesn't get that, it retries.
I used Claude Code to build a Salesforce endpoint that simulates a "Lazy ACK." The server accepts the data but waits 15 seconds before responding. If your n8n instance or AWS Lambda function is configured with a 10-second timeout, you’ve just identified a failure point that a sandbox would never have caught.
We also configured the harness to simulate a "Batch Burst": sending 10 concurrent SOAP requests, each with a 100-record batch. This is how you test if your database can handle 1,000 concurrent writes without a deadlock.
The Chaos Middleware
Once the routes are built, we add a simple /config endpoint to our local server. This allows us to change the server's behavior on the fly using a simple CURL command.
// Chaos middleware generated via Claude Code
app.use((req, res, next) => {
const mode = chaosStore.getMode();
if (mode === 'RATE_LIMIT') {
return res.status(429).json({ message: 'Too many requests' });
}
if (mode === 'JITTER') {
const delay = Math.floor(Math.random() * 8000) + 2000;
return setTimeout(next, delay);
}
next();
});
This setup allows for "Fire Drill" testing. I can run a script that cycles my local environment through 30 seconds of rate limits, followed by a burst of high-latency traffic, followed by malformed JSON. If the automation pipeline drops a single lead during that sequence, the system isn't production-ready.
Trade-offs and Limitations
A local mock server is an ingestion harness, not a full CRM replica.
- OAuth flows: You still need a sandbox to test the initial OAuth handshake and redirect URI logic, as this requires a real identity provider response.
- Side effects: If an Opportunity update in Salesforce triggers an Apex class that then fires a Platform Event, the mock server won't help you. It only tests what happens after the event leaves the CRM.
- Schema Drift: If HubSpot updates their signature version, you must update the mock server. However, with Claude Code, this is usually as simple as pasting the updated documentation into the CLI and saying, "Update the HubSpot generator to match this."
The Shift to GTM Engineering
Moving away from manual sandbox testing toward local chaos testing is a hallmark of GTM Engineering. It shifts the operator's role from a passive consumer of SaaS APIs to a builder who owns the infrastructure's resilience.
When you can simulate a 429 error or a corrupted signature at will, you stop hoping your integrations work and start knowing they can recover. Claude Code makes this accessible. You don’t need to be a full-stack engineer to maintain a 200-line Express server; you just need to be curious enough to ask "what happens if this breaks?" and technically capable enough to build the tool that gives you the answer.
— C.B.