How to Trigger Custom Code from HubSpot Workflows via Webhook
A comprehensive guide on calling Workflood custom code actions in TypeScript or Python directly from HubSpot workflow webhook steps.
Architecture Overview
HubSpot Workflows provide a native **"Send a webhook"** action. By pointing this action to your unique Workflood action webhook URL, you can trigger complex TypeScript or Python scripts immediately when a contact, company, deal, or ticket meets enrollment criteria.
**Key Benefits of this pattern:** - Execute heavy multi-object logic without hitting HubSpot Data Hub limits. - Run Python 3.11 or TypeScript with full npm/pip packages. - Keep 60-second to 5-minute execution timeouts instead of HubSpot's 20-second hard cap.
Configuring the Webhook Action in HubSpot
Follow these steps to wire your HubSpot workflow to Workflood:
- Open your HubSpot Workflow (Contact-based, Deal-based, or Company-based).
- Click the **+ (Plus)** button to add an action and select **Send a webhook**.
- Set the **Method** to `POST`.
- In the **Webhook URL** field, paste your Workflood Action Webhook URL:
- `https://workflood.dev/api/h/[ACTION_ID]?token=[SECRET_TOKEN]`
- Under **Request Body**, select **Customize request body** to pass specific record tokens, or **Include all properties** for full CRM payload transmission.
Recommended Webhook Payload Structure
When configuring customized JSON payloads in HubSpot, structure your payload to include the primary object ID and relevant context properties:
{
"objectId": "{{ contact.hs_object_id }}",
"email": "{{ contact.email }}",
"companyId": "{{ contact.associatedcompanyid }}",
"dealId": "{{ deal.hs_object_id }}",
"amount": "{{ deal.amount }}",
"portalId": 12345678,
"eventType": "DEAL_STAGE_CHANGE"
}Handling the Payload in Your Workflood Handler
In your Workflood TypeScript or Python action, the payload is automatically injected as the first parameter of the `main` handler:
export default async function main(input: {
objectId?: string
email?: string
dealId?: string
amount?: string
[key: string]: unknown
}) {
const raw = Array.isArray(input) ? input[0] : input
const dealId = raw.dealId || raw.objectId
if (!dealId) {
throw new Error('Missing dealId in webhook payload')
}
// Fetch deal details using pre-injected HubSpot SDK
const deal = await hubspot.client.crm.deals.basicApi.getById(dealId, ['dealname', 'amount'])
// Custom computation / enrichment
const formattedArr = Number(deal.properties.amount || 0) * 1.15
// Write back to HubSpot
await hubspot.client.crm.deals.basicApi.update(dealId, {
properties: { projected_expansion_arr: formattedArr.toFixed(2) }
})
return { success: true, dealId, updatedArr: formattedArr }
}Security: Timing-Safe Webhook Token Verification
Every Workflood webhook endpoint includes a cryptographically randomized 64-character token in the query parameters. Requests missing or presenting an invalid token are rejected with a `401 Unauthorized` before code execution or sandbox allocation occurs.
Associate Deals to Marketing Event on Post-Attendance Creation
Automatically link deals created within 3 months of contact marketing event attendance to the attended event for multi-touch revenue attribution.
Frequently Asked Questions
Does HubSpot wait for the Workflood action to finish?
HubSpot webhooks receive an immediate 202 Accepted response upon queueing. Workflood executes the action asynchronously in its dedicated gVisor sandbox and updates HubSpot via the API client.
What happens if the action fails?
Workflood logs the failure with full stack traces, provides a 1-click dry-run replay, and can trigger instant Slack or email alerts to your engineering channel.
