On this page · 9 sections
Overview
The Kustiq HubSpot integration runs B2B enrichment on every HubSpot company and contact in your portal. It writes verified firmographics, tech stack, hiring + funding signals, and contact role data straight into HubSpot properties so your filters, lists, and workflows pick them up without any manual export.
Two surfaces, one pipeline. Companies get 33 enriched properties: industry, headcount band, ARR estimate, funding stage, last round date, tech stack array, hiring signals, and 26 more. Contacts get 4 enriched properties: kustiq_email_confidence, kustiq_contact_role, kustiq_contact_department, kustiq_contact_seniority. That is 37 writeable fields total. Counts match the HowTo schema, the FAQ schema, and the property reference below, in that order.
With Kustiq, a company record refreshes every 24 hours. With raw HubSpot, the same record stays whatever the rep typed at create time.
Setup, in 5 minutes
Six steps. HubSpot-side OAuth, no API key paste, no IP allowlist. Refresh token encrypted at rest, rotated every 6 hours.
Open Integrations in your Kustiq workspace
~ 20 secondsFrom the dashboard, go to Settings → Integrations. Find the HubSpot card, click Connect. You stay signed into Kustiq the whole time.
Authorise the OAuth consent screen
~ 40 secondsHubSpot opens its consent dialog. Pick the portal, review the six scopes (crm.objects.companies.read, crm.objects.companies.write, crm.schemas.companies.read, crm.schemas.companies.write, crm.objects.contacts.read, crm.objects.contacts.write), click Connect app. HubSpot redirects back to Kustiq and the integration card flips to Connected.
Choose what to import
~ 30 secondsPick a HubSpot company list or all companies. Kustiq imports name, domain, and the HubSpot record ID, then matches each row against the Kustiq profile graph. Empty domains are skipped, not enriched.
Confirm the matched profiles
~ 1 minute for 100 rowsKustiq shows the match table: HubSpot name on the left, Kustiq profile on the right, confidence in the middle. Anything below 80% confidence stays unmatched and waits for your review. You confirm and the import queue starts.
Run the first sync
~ 2 minutes for 1,000 rowsClick Sync now. Kustiq writes 33 company properties and 4contact properties to every matched record, in batches of 100, respecting HubSpot’s 100-req/10-sec rate limit. Progress shows per-batch status and skipped reasons.
Verify in HubSpot
~ 30 secondsOpen any synced company in HubSpot. The right sidebar shows a Kustiq section with all 33 company properties, prefixed kustiq_*. The 4 contact properties land on the contact card, same prefix. From now on, the sync runs every 24 hours.
Property reference
Every property is namespaced kustiq_* so it never collides with anything you already have. 33 company + 4 contact = 37 enriched properties. Counts match the HowTo + FAQ schemas. If a number disagrees somewhere, this section wins.
Company properties
33 fields- kustiq_industryenum
- kustiq_headcount_bandenum
- kustiq_arr_estimatenumber
- kustiq_funding_stageenum
- kustiq_last_round_datedate
- kustiq_last_round_amountnumber
- kustiq_tech_stackstring[]
- kustiq_hiring_signalenum
- kustiq_hq_citystring
- kustiq_hq_countrystring
- kustiq_remote_sharenumber
- kustiq_score_anumber
- kustiq_score_bnumber
- kustiq_score_cnumber
- 19 more (operations, GTM signals, fit scores). Pulled every 24 hours into the same
kustiq_*namespace.
Contact properties
4 fields- kustiq_email_confidencenumber
- kustiq_contact_roleenum
- kustiq_contact_departmentenum
- kustiq_contact_seniorityenum
These are the only contact-side writes Kustiq performs. No name, no email, no phone is overwritten. Email confidence is read-only output, never input.
Connect your HubSpot in 5 minutes.
Free tier: 3 profiles a week, no card. The full property reference writes on the first sync.
Permissions and scopes
Kustiq requests six HubSpot scopes, no more. You can revoke any of them from HubSpot → Settings → Integrations without contacting support.
crm.objects.companies.read· read native HubSpot company fields (name, domain, industry, numberofemployees) for matching against the Kustiq profile graph.crm.objects.companies.write· write the 33kustiq_*company properties on matched records.crm.schemas.companies.read· check thekustiq_*property group exists and matches Kustiq’s expected schema on every sync.crm.schemas.companies.write· create thekustiq_*property group on first connect, once per portal.crm.objects.contacts.read· read contact name, email, associations so contact role and seniority can be attributed to the right person.crm.objects.contacts.write· write the 4kustiq_*contact properties (email confidence, role, department, seniority). No native contact field is ever overwritten.
Kustiq does not request files, tickets, e-commerce, deals, or any conversation scope. If your IT review asks for a written list of what we touch, the six lines above are the answer.
Webhooks
Kustiq sends a webhook to your endpoint every time a company or contact is enriched. Each request is signed with HMAC-SHA256 over the raw body, using a shared secret you generate per workspace.
The signature lives in the X-Kustiq-Signature header as a bare 64-character hex digest. The body has a top-level timestamp field (unix seconds) for replay protection. Reject any request whose computed signature does not match in constant time. Reject any request whose body timestamp is older than 5 minutes.
// Express handler. Use express.raw({ type: "application/json" }). const crypto = require("crypto"); const SECRET = process.env.KUSTIQ_WEBHOOK_SECRET; function verify(req) { const sig = req.headers["x-kustiq-signature"] || ""; if (sig.length !== 64) return false; const mac = crypto .createHmac("sha256", SECRET) .update(req.body) .digest("hex"); const ok = crypto.timingSafeEqual( Buffer.from(mac, "hex"), Buffer.from(sig, "hex"), ); if (!ok) return false; // Replay check: body has top-level "timestamp" (unix seconds). const body = JSON.parse(req.body); return Date.now() / 1000 - body.timestamp < 300; }
Retry policy: 5xx response or no response inside 10s triggers exponential backoff (1m, 5m, 30m, 2h, 12h) for up to 24 hours, then the event is dropped and logged.
Sync rules
- Cadence.Every 24 hours, off-peak in your portal’s region (EU portals run between 02:00 and 04:00 CET).
- Direction. One way, Kustiq to HubSpot. We never read contact email content, deal data, or activity.
- Conflict. Kustiq only writes
kustiq_*properties. Native HubSpot fields (industry,numberofemployees) are read for matching, never overwritten. - Match key. Domain first, name fallback. Confidence below 80% never writes.
- Rate limit. 100 requests / 10 seconds, batched. Kustiq backs off automatically on 429.
- Disconnect. Revoking from HubSpot stops new writes.
kustiq_*properties stay on records until you delete the property group.
Troubleshooting
Twelve known states. Each has a stable anchor so you can link a teammate to the exact row.
OAuth token rejected by HubSpot #
The refresh token was revoked from HubSpot’s side. Reconnect from Settings → Integrations. Existing kustiq_* properties stay on records.
Missing scope crm.objects.companies.write #
The connecting user is not a HubSpot Super Admin and the portal blocked the scope. Ask a Super Admin to reconnect, or grant the scope to the user role.
Property group kustiq_* already exists with conflicting types #
Someone created kustiq_industry manually as a single-line text. Delete the manual property, run sync again. Kustiq will recreate it as enum.
Rate limit hit, sync paused #
Another integration is consuming HubSpot’s daily limit. Kustiq waits, retries on the schedule above. No action needed unless the queue grows past 6 hours.
Match confidence under 80% #
The HubSpot row has no domain or a generic one (gmail, hotmail). Add a domain on the company record, or drop the row from the synced list.
Empty domain on company record #
Kustiq skips matching when the HubSpot domain field is blank. Bulk-set the domain in HubSpot, then re-run sync.
Custom kustiq_* property locked as read-only #
A workflow toggled the property to read-only. Unlock from Settings → Properties, or let Kustiq manage the entire kustiq_* group.
HubSpot portal in trial-paused state #
HubSpot freezes write access on expired trials. Reactivate the portal, then sync resumes within 10 minutes.
Webhook signature mismatch #
Most likely the body was parsed as JSON before signing was checked, or the secret on your side drifted from Kustiq’s. Verify on the raw body bytes (no whitespace re-encoding); rotate the secret from Settings → Webhooks → Rotate if drift is suspected.
Webhook body timestamp older than 5 minutes #
Server clock drift. Sync your endpoint host with NTP. Kustiq’s body timestamp field is always in UTC unix seconds.
Workspace region differs from HubSpot portal region #
EU workspace connecting to a US portal is allowed but data crosses regions. Move the workspace from Settings → Region, then reconnect.
Free tier hit weekly profile limit #
Free workspaces enrich 3 profiles a week. Upgrade to Insight ($39/mo) for 200 credits, or Pro ($119/mo) for 800 credits.
FAQ
How many properties does Kustiq write to HubSpot?
Does Kustiq overwrite native HubSpot fields like industry or numberofemployees?
kustiq_* namespace. Native HubSpot fields are read during matching, never modified. If you want to mirror a Kustiq value into a native field, build a HubSpot workflow.What scopes does the integration need?
crm.objects.companies.read, crm.objects.companies.write, crm.schemas.companies.read, crm.schemas.companies.write, crm.objects.contacts.read, crm.objects.contacts.write. The full list and what each one does is in the Permissions section.Can I use the integration on the free tier?
How do I disconnect Kustiq from HubSpot?
Settings → Integrations → Kustiq → Uninstall. From Kustiq: Settings → Integrations → HubSpot → Disconnect. Either revokes the OAuth token within 5 minutes. Existing kustiq_* properties stay on records until you delete the property group.Where is the data stored?
Settings → Region before first connect; moving regions later is a manual support request.What happens if HubSpot rate-limits the sync?
Changelog
- 2026-05-16 · v2.1 Pair-lock production-ready audit. Scope list corrected to six (
crm.objects.companies.read/write,crm.schemas.companies.read/write,crm.objects.contacts.read/write) to match the actual OAuth grant. Webhook verifier snippets rewritten to match the bare-hexX-Kustiq-Signatureheader the server emits. Free-tier copy unified to 3 profiles a week across hero, mid-CTA, final CTA, and JSON-LD. Pricing fixed inERR_QUOTA_FREE(Insight 200 credits, Pro 800 credits). JSON-LD @id-graph linked to root#organd#site. - 2026-05-08 · v2.0 Property count clarified to 33 + 4 = 37 across docs, JSON-LD, and OG. Webhook section adds verification snippets. Six setup-step screenshots wired to HowToStep schema. New “Last verified” badge.
- 2026-04-12 · v1.4 Added
kustiq_score_a/b/cICP-fit tier properties. Bumped batch size from 50 to 100. - 2026-02-28 · v1.3 EU region (Frankfurt) opened. Refresh-token rotation cut from 24h to 6h.
- 2025-11-04 · v1.2 Match-confidence floor raised to 80%, with
ERR_MATCH_LOWsurfaced. - 2025-08-19 · v1.0 Initial release.
HubSpot, enriched on the next sync.
3 profiles a week, no card. The integration writes 33 company + 4 contact properties on the first run.