How to Test HubSpot Webhooks
If your application needs to sync data with a sales team, you are likely integrating with HubSpot. HubSpot uses webhooks to notify your system when records change—like when a new Contact is created, a Deal stage is updated, or a Company property is modified.
HubSpot webhooks can be dense, and their security model requires specific handling. Here is a guide to testing and debugging HubSpot webhooks during development.
The anatomy of a HubSpot webhook
Like SendGrid, HubSpot batches events to reduce network traffic. A single HTTP POST request to your endpoint will contain a JSON array of event objects, rather than a single event.
A typical payload for a contact creation event looks like this:
[
{
"eventId": 123456789,
"subscriptionId": 98765,
"portalId": 456789,
"appId": 112233,
"occurredAt": 1709251200000,
"subscriptionType": "contact.creation",
"attemptNumber": 0,
"objectId": 1001,
"propertyName": "email",
"propertyValue": "[email protected]"
}
]
Notice that the payload gives you the objectId (the ID of the new contact) and the specific propertyName that triggered the event, but it does not give you the entire contact record. You often have to use the objectId to make a separate API call back to HubSpot to fetch the full details of the contact.
Setting up a reliable test endpoint
Stop reading raw JSON
Payloader shows you what your HubSpot webhook actually did — in plain English. See the event, amount, status, and more at a glance.
Start free trial →Before writing the logic to process these arrays and fetch secondary data, you need to verify exactly what HubSpot is sending for your specific subscriptions.
Instead of dumping the raw JSON into your terminal, use a dedicated inspector like Payloader:
- Create an endpoint URL in Payloader.
- In your HubSpot Developer account, navigate to your app, select "Webhooks", and paste the Payloader URL as the target.
- Create a subscription for "Contact creation" and activate it.
- Trigger a test event or manually create a test contact in your connected HubSpot portal.
Payloader captures the payload immediately. It automatically identifies the HubSpot format, extracts the subscriptionType and the affected objectId, and presents them in a clean summary. You can instantly see exactly which properties were passed without scanning the raw array.
Local testing and proxying
To write the backend code that updates your local database when a HubSpot deal closes, you need those webhook payloads routed to your localhost.
Use Payloader to forward the captured HubSpot webhooks directly to your local development server. This allows you to work without managing fragile ngrok tunnels.
When your local handler throws an error because it failed to parse the occurredAt timestamp correctly, simply click "Replay" in the Payloader UI. The exact same payload will be re-sent to your local environment instantly, saving you from having to create another dummy contact in HubSpot.
Verifying the v3 signature
HubSpot requires strict signature verification to ensure requests are authentic. They currently use a "v3" signature format.
When HubSpot sends a request, it includes an X-HubSpot-Signature-v3 header. The verification process involves taking the HTTP method (POST), the full requested URI, the raw request body, and a timestamp header (X-HubSpot-Request-Timestamp).
You concatenate these strings together and hash them using an HMAC-SHA256 algorithm with your HubSpot App's Client Secret. If your calculated hash matches the header, the request is valid. You must also verify that the timestamp is within 5 minutes of the current time to prevent replay attacks.
Because this verification requires the exact, unparsed raw body, debugging it can be frustrating. Using an inspector to view the raw bytes ensures your hashing logic is working with the correct data.