
Updated June 18, 2026 by Sunny Chauhan.
The first three founders we worked with on HubSpot Marketplace apps each made the same mistake: they wired their app to the wrong webhook system. One subscribed to workflow webhooks for an app that should have used CRM object webhooks. One built an "app installed" event listener using the workflow webhooks system that doesn't fire at install. Both got rejected from certification and had to redo a week of work. HubSpot has three webhook flavors and they are not interchangeable. This guide walks through what each one is for, when to use which, how to verify signatures properly, and the certification gotchas that catch first-time builders.
Pro Tip
TL;DR HubSpot offers three distinct webhook systems: 1/ App webhooks (subscribed via Developer Account, fire on CRM object changes for installed apps), 2/ Workflow webhooks (fire from inside a customer-built workflow, scoped to the customer's portal), and 3/ Form submission webhooks. App webhooks are the right choice for most Marketplace apps. Verify every payload with the X-HubSpot-Signature-v3 header against your client secret. The HubSpot retry policy backs off over 24 hours and gives up if your 200 response rate drops below 95% (the same threshold that affects certification).
What HubSpot webhooks actually do
A webhook is HubSpot calling your server when something happens in a customer's portal. The customer didn't ask your server for the event; your server didn't poll for it. HubSpot pushes the event payload to a URL you registered and expects a 200 response within 5 seconds.
That's the boring definition. The interesting part is which "something happens" you can subscribe to, and that depends on which of the three webhook systems you use.
→ App webhooks subscribe to CRM object lifecycle events (contact created, deal property changed, ticket merged, etc.) for any customer who installs your app. You configure subscriptions once at the app level in your Developer Account. The webhook fires for every customer.
→ Workflow webhooks fire from inside a customer-built workflow when the workflow's logic decides to call your URL. The customer adds your URL as an action. Scope is one customer's portal at a time.
→ Form submission webhooks fire when a HubSpot form is submitted. Mostly used for marketing-side data capture.
For a Marketplace app that reacts to CRM data changes (which is most apps), the right choice is app webhooks. The other two are situational.
Setting up app webhooks: the actual flow
You configure app webhooks from your Developer Account, not from individual customer portals. The setup has three parts: target URL, subscription objects, and the optional throttle.
1/ Set the target URL. In your Developer Account, go to your app's settings and add the webhook target URL. This is your server endpoint that receives POST payloads. It must be publicly reachable and respond with 200 within 5 seconds.
2/ Choose subscription objects. HubSpot exposes subscriptions for contact, company, deal, ticket, line item, product, conversation, and a handful of custom object events. For each object you can subscribe to creation, deletion, property changes, association changes, and merge events.
3/ Configure the throttle (optional but recommended). You can throttle how many events HubSpot sends per second per account. For most apps the default is fine. If your server is constrained, lower the rate.
After this setup, when a customer installs your app and you have the correct scopes (crm.objects.contacts.read, etc.) HubSpot starts sending events for that customer's portal to your URL.
The payload structure
Every app webhook delivery is an array of events. HubSpot batches events to reduce request count. A typical payload looks like:
``json [ { "eventId": 1234567890, "subscriptionId": 9876, "portalId": 12345, "appId": 67890, "occurredAt": 1718726400000, "subscriptionType": "contact.propertyChange", "attemptNumber": 0, "objectId": 401, "propertyName": "lifecyclestage", "propertyValue": "customer", "changeSource": "CRM_UI" } ] ``
Important fields:
→ portalId tells you which customer's portal generated the event. Your handler must route the event to the right customer record on your side.
→ subscriptionType tells you what kind of event it is.
→ attemptNumber is HubSpot's retry counter. If you see attempt 3, your server has failed twice already.
→ objectId is the CRM record id. To get the rest of the record's properties you need to call the CRM API with the OAuth token for that portal.
That last point catches founders. The webhook payload doesn't carry the full record. It carries the change notification. To act on the data you have to fetch it. That doubles the API calls if you're not careful (see the rate-limit guide).
Signature verification: do this every time
HubSpot signs every webhook delivery with HMAC-SHA256 against your app's client secret. The signature lives in the X-HubSpot-Signature-v3 header. You must verify it before processing the payload. An unsigned or invalidly-signed request might be an attacker spoofing HubSpot.
The v3 signature scheme uses your app's client secret as the HMAC key, and the canonicalized payload string as the message. The canonicalization is: <method><uri><body><timestamp> where timestamp comes from the X-HubSpot-Request-Timestamp header.
A minimal Node.js verifier:
```javascript const crypto = require('crypto');
function verifyHubSpotSignature(req, clientSecret) { const signature = req.headers['x-hubspot-signature-v3']; const timestamp = req.headers['x-hubspot-request-timestamp'];
if (!signature || !timestamp) return false;
const fiveMinutes = 5 60 1000; if (Math.abs(Date.now() - parseInt(timestamp)) > fiveMinutes) { return false; }
const rawString = ${req.method}${req.url}${req.rawBody}${timestamp}; const computed = crypto .createHmac('sha256', clientSecret) .update(rawString) .digest('base64');
return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(computed) ); } ```
Three things worth flagging:
1/ Use rawBody. If your framework JSON-parses the request body before you get it, the signature will not match. You need the original byte string.
2/ Use a timing-safe comparison. A regular === is vulnerable to timing attacks. Use crypto.timingSafeEqual in Node, hmac.compare_digest in Python.
3/ Reject requests with a stale timestamp (older than 5 minutes). Replay attacks otherwise.
Retry behavior and the 95% rule
HubSpot retries failed webhook deliveries with exponential backoff for up to 24 hours. If your server returns a non-2xx response or fails to respond within 5 seconds, HubSpot waits and tries again. The retry intervals start short (seconds) and stretch out.
Two things that matter for builders:
→ The retry chain doesn't help you if your server is consistently down. HubSpot gives up after the 24-hour window even if it never reached you.
→ The success rate counts toward Marketplace certification. Your app must maintain a 95% average success rate across all webhook deliveries. If you keep tripping under that, certification will reject your app or revoke an existing certification.
The pattern I'd recommend: ack the webhook fast, process async. Return 200 immediately after pushing the payload to a queue (SQS, Pub/Sub, your own DB). Process the actual business logic in a worker. This keeps your acknowledgment time consistently under 5 seconds and your success rate above 95%, no matter how slow the downstream processing is.
App webhooks vs workflow webhooks: when to use which
I keep seeing builders pick this wrong. The simple test:
→ Use app webhooks when you want to react to a CRM event for every customer that installs your app, automatically, without the customer configuring anything. Example: an app that syncs deal stage changes to your billing platform. The customer doesn't have to set up a workflow; once they install, deal changes flow.
→ Use workflow webhooks when you want the customer to decide which events trigger your app, and you're OK with the customer building a workflow as the entry point. Example: an app that runs an AI summary when a specific kind of contact reaches a specific lifecycle stage. The customer's workflow filters the trigger; your URL gets the result.
→ Use form submission webhooks when you specifically need form data routed to your server. Mostly relevant for marketing tooling.
If your product is an "always-on" CRM extension, you want app webhooks. If your product is "customer opts in event-by-event," workflow webhooks. If you're building forms tooling, form webhooks.
How this maps to Salesforce-side experience
If you've shipped Salesforce Managed Packages before, the equivalent of HubSpot app webhooks is Platform Events combined with Apex triggers. Both are publisher-subscribed event streams that fire on CRM changes. The HubSpot version is simpler operationally (HTTP POST instead of CometD or pub/sub long-poll) but the architectural lift is roughly the same.
At Appnigma we generate 2GP Managed Packages for Salesforce, and the patterns we apply to package-level events (debounce, retry, idempotency, signature verification) transfer one-to-one to HubSpot webhooks. The vendor APIs differ; the architecture doesn't.
Pre-flight checklist before submitting an app with webhooks
[ ] Picked the right webhook system (app vs workflow vs form) for your app's intent → Yes / No
[ ] Webhook target URL is publicly reachable and responds in under 5 seconds → Yes / No
[ ] Signature verification using
X-HubSpot-Signature-v3in place → Yes / No[ ] Timing-safe HMAC comparison (not
===) → Yes / No[ ] Timestamp staleness check (reject older than 5 minutes) → Yes / No
[ ] Acknowledge fast, process async (queue + worker pattern) → Yes / No
[ ] Success rate monitoring per portal in place → Yes / No
[ ] Tested behavior when HubSpot retries (idempotent handler) → Yes / No
[ ] Subscription scopes match what you'll request in OAuth consent → Yes / No
Real-world scenario: a meeting intelligence app gets webhooks right
A meeting intelligence product (analogous to Avoma) wanted to log meeting summaries against the relevant HubSpot Deal record. The naive approach: poll the HubSpot CRM every 5 minutes for deal updates. The cost: hundreds of unnecessary API calls and a stale UX.
The webhook approach: subscribe to deal.propertyChange for deal stage and amount. When the customer's rep updates a deal after a meeting, the webhook fires. The product fetches the deal, finds the most recent meeting summary, attaches the summary to the deal's activity timeline.
The first version of the handler failed the 5-second timeout under load because it tried to do the summary attachment synchronously. They moved to ack-fast-then-process and the failure rate dropped to under 0.5%. Certification passed on the next submission.
Frequently Asked Questions
What is a HubSpot webhook?
A HubSpot webhook is an HTTP POST that HubSpot sends to your server when something happens in a customer's portal: a contact is created, a deal stage changes, a workflow fires, a form is submitted. Your server registers a target URL once and HubSpot calls it on the relevant events. See the HubSpot Webhooks API docs.
What is the difference between app webhooks and workflow webhooks?
App webhooks are subscriptions you configure at the app level in your Developer Account. They fire for every customer who installs your app. Workflow webhooks are added by customers as a workflow action and fire only when that specific customer's workflow runs. App webhooks are the right choice for most Marketplace apps; workflow webhooks suit per-customer opt-in event flows.
How do I verify a HubSpot webhook signature?
Use the X-HubSpot-Signature-v3 header. Compute HMAC-SHA256 over <method><uri><body><timestamp> using your app's client secret as the key, base64-encode the result, and compare timing-safely to the header value. Reject requests where the timestamp is older than 5 minutes.
What is the HubSpot webhook retry policy?
HubSpot retries failed deliveries with exponential backoff for up to 24 hours. Deliveries that consistently fail count against your app's success rate, which must stay above 95% for Marketplace certification (HubSpot Marketplace certification requirements).
How fast must my webhook handler respond?
Within 5 seconds. Longer than that and HubSpot treats the delivery as failed and retries. The reliable pattern is to acknowledge the webhook fast (queue the payload, return 200) and process the business logic asynchronously in a worker.
Does the 95% success rate include manual retries from customers?
The success rate is computed across all delivery attempts. If your server returns 500 and HubSpot retries successfully, that counts as a delivery that took multiple attempts but ultimately succeeded. Persistent failures push the rate down.
How do I get the full record after a property change webhook?
The webhook payload carries the change notification and the objectId, not the full record. To get the rest you call the CRM API for that object id using the OAuth token for the portal that generated the event. See our API key management guide for handling per-portal tokens.
Are there rate limits on webhook deliveries themselves?
Yes. HubSpot caps webhook deliveries at a per-account throttle that you can configure in your app settings. The cap is separate from the 100 requests / 10 seconds API rate limit. Deliveries over the throttle are queued and sent in subsequent windows.
About the author
Sunny Chauhan is the founder and CEO of Appnigma AI, a no-code platform that generates Salesforce AppExchange-ready Managed Packages from natural-language prompts. He holds Salesforce certifications in Platform Developer II, Platform App Builder, Administrator, Data Cloud Consultant, and AI Associate. The architectural patterns Appnigma applies to Salesforce Platform Events and event-driven Managed Package code (idempotency, signature verification, ack-fast-process-async) transfer directly to HubSpot webhook implementations.
Originally published June 18, 2026. Last reviewed June 18, 2026. Webhook system descriptions verified against HubSpot's developer documentation and Marketplace certification requirements current as of the published date.
Related articles
Sources
1/ HubSpot Developers, Webhooks API documentation 2/ HubSpot Marketplace Certification Requirements 3/ HubSpot Developers, App Webhook Setup Guide 4/ HubSpot Community, Signature verification thread
Which webhook system did you pick for your app, and what made you sure it was the right one?
Ready to transform your Salesforce experience?
Start exploring the Salesforce Exchange today and discover apps that can take your CRM efficiency to the next level.
