HubSpot workflows can call external APIs using Custom Code actions. If your external endpoint requires a bearer token for authentication (like an AWS Lambda function URL or a custom API), you need to store the token securely and pass it in the request header. This guide shows you how to set up a bearer token in a HubSpot workflow using Python custom code and HubSpot Secrets.
Prerequisites
- A HubSpot account with access to Workflows (Professional or Enterprise plan)
- A bearer token from your external service
- An active workflow where you want to add the API call
How HubSpot Secrets Work
HubSpot Secrets let you store sensitive values (API keys, tokens, passwords) that your custom code can access at runtime. Secrets are encrypted and never visible in the code editor after saving. In Python custom code, you retrieve them using os.environ.get(), just like environment variables.
This is the right way to handle credentials — never hardcode tokens directly in your custom code.
Setting Up the Bearer Token Step by Step
1. Add a Custom Code Action
In your workflow, click the + button to add an action and select Custom Code. Set the language to Python 3.9 (the only Python version HubSpot currently supports).
2. Create a Secret for Your Token
In the Custom Code editor, find the Secrets section and click Add secret.
- Secret name:
BearerToken(or any name you prefer — you’ll reference this in code) - Secret value: paste your token value only (without the “Bearer ” prefix)
Store just the raw token and add the “Bearer ” prefix in your code. This keeps the secret reusable — if you later need the token for a different auth scheme, you won’t need to create a new secret.
3. Add Input Properties
Under the Properties section, add hs_object_id. This passes the HubSpot record ID that triggered the workflow into your code, so you can include it in the API request payload.
You can add other properties too (like email, firstname, or custom properties) depending on what your external API needs.
4. Write the Custom Code
Here’s a working example that calls an external endpoint with the bearer token:
import requests
import os
def main(event):
# Get the HubSpot record ID from input properties
record_id = event["inputFields"]["hs_object_id"]
# Get the token from HubSpot Secrets
token = os.environ.get("BearerToken")
if not token:
return {
"outputFields": {
"status": "error",
"message": "BearerToken secret is not configured"
}
}
# Your external API endpoint
url = "https://your-api-endpoint.example.com/process"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
payload = {
"recordId": record_id
}
try:
response = requests.post(url, headers=headers, json=payload, timeout=15)
response.raise_for_status()
return {
"outputFields": {
"status": "ok",
"response_code": response.status_code,
"response_body": response.text
}
}
except requests.exceptions.RequestException as e:
return {
"outputFields": {
"status": "error",
"message": str(e)
}
}
Key parts of this code:
os.environ.get("BearerToken")— retrieves the secret you stored in step 2f"Bearer {token}"— prepends the “Bearer ” prefix for the Authorization headertimeout=15— prevents the request from hanging indefinitely (HubSpot custom code has a 20-second execution limit)raise_for_status()— raises an exception for HTTP 4xx/5xx responses so errors are caughtoutputFields— makes values available to subsequent workflow actions
5. Save and Test
Save the custom code action, then test it by enrolling a record in the workflow. Check the workflow execution log to see the output fields and confirm the external API responded correctly.
Validating the Token on the Receiving End
If your external endpoint is an AWS Lambda function, you’ll want to validate the bearer token before processing the request. Here’s a minimal check:
import os
import json
EXPECTED_TOKEN = os.environ["BEARER_TOKEN"]
def lambda_handler(event, context):
auth_header = event.get("headers", {}).get("authorization", "")
if auth_header != f"Bearer {EXPECTED_TOKEN}":
return {"statusCode": 401, "body": json.dumps({"error": "Unauthorized"})}
# Token is valid — process the request
body = json.loads(event.get("body", "{}"))
record_id = body.get("recordId")
return {"statusCode": 200, "body": json.dumps({"received": record_id})}
Store the expected token in the Lambda function’s environment variables. For a more secure approach, you could store the token in AWS Secrets Manager instead.
Things to Watch Out For
- 20-second timeout. HubSpot custom code actions have a hard 20-second execution limit. Set a
timeouton your HTTP request to avoid hitting this silently. - No pip install. You can’t install additional Python packages. Only
requestsand the standard library are available. - Python 3.9 only. HubSpot doesn’t support other Python versions in custom code yet.
- Secret name casing. The secret name is case-sensitive in
os.environ.get(). If your secret is namedBearerToken, you must use exactly"BearerToken"in code. - Retry on failure. If your external API can be flaky, consider adding retry logic. See How to Make Reliable HubSpot API Requests in Python (With Retry Logic) for a pattern you can adapt.
Conclusion
Storing your bearer token in HubSpot Secrets and accessing it with os.environ.get() keeps your credentials out of the code while letting your workflow call any authenticated external API. Add a timeout, handle errors, and validate the token on the receiving side to keep the integration reliable.
If you’re building a full HubSpot-to-AWS pipeline, check out Sync HubSpot Company Records to S3 Using AWS Lambda and Step Functions. For linking records after your workflow creates them, see How to Use HubSpot CRM v4 Associations.


