Developer docs
Integration recipe
HubSpot
Enrich a contact the moment it enters HubSpot
Endpoint
POST /api/v1/leads/enrich?mode=sync
Cost
1 enrichment credit per contact (shared with your dashboard quota)
Latency
20–40 s inline (sync mode); use async + webhook if you expect bursts
HubSpot workflow custom-code actions have a 20 s execution limit on Pro and 60 s on Enterprise. If your enrichments routinely exceed that, switch to the async pattern at the bottom of this page.
- Step 1
Create a scoped API key
In LeadIQ Pro → Settings → API, create a key labelledHubSpot workflow. Copy theliq_live_…secret once — it won't be shown again. - Step 2
Create custom contact properties in HubSpot
In HubSpot → Settings → Properties → Contact properties, create:leadiq_opportunity_score(Number)leadiq_tags(Multiline text)leadiq_summary(Multiline text)leadiq_hiring_signals(Multiline text)leadiq_opening_line(Single line text)
- Step 3
Build a workflow
Automation → Workflows → Create workflow → Contact-based. Enrollment trigger:
"Contact property Email is known AND Contact property Company is known." Add a Custom code action (requires Operations Hub Professional or above). - Step 4
Paste the custom code
// HubSpot Workflow Custom Code — Node 18 // Secrets: set LEADIQ_API_KEY as a workflow secret (don't inline it) exports.main = async (event, callback) => { const email = event.inputFields['email']; const company = event.inputFields['company']; const domain = email && email.includes('@') ? email.split('@')[1] : null; if (!domain || !company) return callback({ outputFields: {} }); const resp = await fetch("https://leadiqpro.io/api/v1/leads/enrich?mode=sync", { method: "POST", headers: { "Authorization": "Bearer " + process.env.LEADIQ_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ lead: { email, name: event.inputFields['firstname'] + ' ' + event.inputFields['lastname'], title: event.inputFields['jobtitle'], company, domain, }, }), }); if (!resp.ok) { const retryAfter = resp.headers.get('retry-after'); throw new Error('LeadIQ ' + resp.status + ' — retry-after=' + retryAfter); } const data = await resp.json(); const e = data.enrichment || {}; callback({ outputFields: { leadiq_opportunity_score: e.opportunity_score, leadiq_tags: (e.tags || []).join(', '), leadiq_summary: e.company_overview?.summary || '', leadiq_hiring_signals: (e.intent_signals?.hiring_signals || []).join('\n'), leadiq_opening_line: e.engagement_playbook?.opening_line || '', }, }); }; - Step 5
Map output fields to properties
Under Output fields, add one row per custom property (leadiq_opportunity_score,leadiq_tags, …). After the custom-code action, add a Copy property value step mapping each output to the matching contact property. - Step 6
Test with one contact
Toggle the workflow on, then enrol a single test contact. You should see the custom properties populate within ~40 s. If you get a429 upstream_full, you've hit the platform-wide ceiling — retry in a few seconds (see the rate-limit reference). - Step 7
(Optional) Async pattern for higher volume
For higher volume or longer-tail accounts, call the async endpoint without?mode=sync, pass acallback_urlpointing at a HubSpot webhook, and update the contact in the webhook handler. See the webhook payload shape on the overview page.