Integration · HubSpot CRM

HubSpot enrichment, 37 fields per company, refreshed daily.

Connect HubSpot in 5 minutes and Kustiq writes 37 enriched fields onto every company and contact: 33 company properties, 4 contact properties, refreshed every 24 hours from live signals.

Last updated 2026-05-16Last verified · 2026-05-16v2.1 releaseChangelog
3 profiles a week, no cardOAuth 2.0 · revocableEU + US regionscrm.objects.companies.writeGDPR + DPA ready
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 seconds

From 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 seconds

HubSpot 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 seconds

Pick 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 rows

Kustiq 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 rows

Click 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 seconds

Open 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 33 kustiq_* company properties on matched records.
  • crm.schemas.companies.read · check the kustiq_*property group exists and matches Kustiq’s expected schema on every sync.
  • crm.schemas.companies.write · create the kustiq_* 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 4 kustiq_* 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.

POST /webhooks/kustiq
// 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.

ERR_HS_401

OAuth token rejected by HubSpot #

The refresh token was revoked from HubSpot’s side. Reconnect from Settings → Integrations. Existing kustiq_* properties stay on records.

ERR_HS_403

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.

ERR_HS_409

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.

ERR_HS_429

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.

ERR_MATCH_LOW

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.

ERR_DOMAIN_EMPTY

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.

ERR_PROP_READONLY

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.

ERR_PORTAL_PAUSED

HubSpot portal in trial-paused state #

HubSpot freezes write access on expired trials. Reactivate the portal, then sync resumes within 10 minutes.

ERR_WEBHOOK_SIG

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.

ERR_WEBHOOK_STALE

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.

ERR_REGION_MISMATCH

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.

ERR_QUOTA_FREE

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?
37 in total: 33 company + 4 contact properties. HowTo schema, FAQ JSON-LD, and the reference table above all match. If a number disagrees anywhere, file a doc bug.
Does Kustiq overwrite native HubSpot fields like industry or numberofemployees?
Kustiq only writes properties under the 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?
Six: 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?
The integration itself connects on every plan. The free tier enriches 3 profiles a week, so you can wire HubSpot end to end and verify the sync, then upgrade to Insight or Pro to enrich the rest of your portal.
How do I disconnect Kustiq from HubSpot?
Two paths. 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?
EU workspaces store in Frankfurt, US workspaces store in Virginia. Refresh tokens are encrypted at rest with AES-256, rotated every 6 hours. Pick your region in Settings → Region before first connect; moving regions later is a manual support request.
What happens if HubSpot rate-limits the sync?
Kustiq detects 429 responses and backs off on an exponential schedule (1m, 5m, 30m, 2h, 12h) for up to 24 hours. The sync resumes from the last successful batch, no duplicate writes.

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-hex X-Kustiq-Signature header the server emits. Free-tier copy unified to 3 profiles a week across hero, mid-CTA, final CTA, and JSON-LD. Pricing fixed in ERR_QUOTA_FREE (Insight 200 credits, Pro 800 credits). JSON-LD @id-graph linked to root #org and #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/c ICP-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_LOW surfaced.
  • 2025-08-19 · v1.0 Initial release.
Ship it · Free tier

HubSpot, enriched on the next sync.

3 profiles a week, no card. The integration writes 33 company + 4 contact properties on the first run.