Runtimes & SDKs
5 min readUpdated August 2026

Writing Python 3.11 Actions for HubSpot Workflows

A practical guide to building, testing, and deploying custom Python 3.11 workflow actions for HubSpot using the official hubspot-api-client.

The Python 3.11 Runtime Environment

Workflood offers first-class **Python 3.11** execution for teams that prefer Python's rich data manipulation and mathematical capabilities over JavaScript.

**Pre-Installed Python Libraries:** - `hubspot-api-client` (Official HubSpot Python SDK) - `requests` & `urllib3` (HTTP Networking) - `pydantic` & `marshmallow` (Data validation) - Standard library modules (`datetime`, `json`, `math`, `re`, `hashlib`)

Python Action Structure

A Python action in Workflood defines a `main(input)` function that accepts a dictionary payload and returns a dictionary response:

lead_scoring.py
import os
import datetime
from hubspot import HubSpot
from hubspot.crm.contacts import SimplePublicObjectInput

def main(event):
    """
    Workflood Python 3.11 Action Handler
    """
    raw = event[0] if isinstance(event, list) else event
    contact_id = raw.get("objectId") or raw.get("contactId")
    
    if not contact_id:
        return {"error": "No contact ID provided", "processed": False}
    
    # Initialize HubSpot Client
    client = HubSpot(access_token=os.environ.get("HUBSPOT_ACCESS_TOKEN"))
    
    # Fetch contact properties
    contact = client.crm.contacts.basic_api.get_by_id(
        contact_id=contact_id,
        properties=["email", "jobtitle", "annualrevenue", "num_employees"]
    )
    
    props = contact.properties
    score = 50
    
    # Calculate custom lead score
    if "director" in (props.get("jobtitle") or "").lower():
        score += 25
    if "vp" in (props.get("jobtitle") or "").lower() or "c-level" in (props.get("jobtitle") or "").lower():
        score += 35
    if float(props.get("annualrevenue") or 0) > 1000000:
        score += 20
        
    score = min(100, score)
    
    # Update HubSpot Contact
    update_input = SimplePublicObjectInput(properties={"calculated_fit_score": str(score)})
    client.crm.contacts.basic_api.update(contact_id=contact_id, simple_public_object_input=update_input)
    
    return {
        "contact_id": contact_id,
        "score": score,
        "updated_at": datetime.datetime.utcnow().isoformat()
    }

Comparing TypeScript and Python in Workflood

FeatureTypeScript (Node 20)Python (3.11)
**Best For**High-throughput webhooks, async I/O, API orchestrationData parsing, regex cleanup, statistical lead scoring
**SDK Object**hubspot.client (Pre-injected)HubSpot(access_token=...)
**Timeout Limit**60s (Pro) to 300s (Agency)60s (Pro) to 300s (Agency)
**Container Sandboxing**gVisor micro-containergVisor micro-container
Turnkey Recipe Available

Contact Deduplication

Find and merge duplicate contacts by email address.

Frequently Asked Questions

Can I use Pandas or NumPy in Python actions?

Lightweight data operations using native Python and standard math libraries are supported out of the box. High-memory data science libraries are available under dedicated Enterprise sandbox pools.