tool.hubspot_integration.5ebd51c72e954598

SkillProductivity

"Build reliable HubSpot \u2194 Airtable sync workflows. Covers API selection,\

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the tool.hubspot_integration.5ebd51c72e954598 skill

What this skill tells your AI

The instructions your AI receives, as published by ai45lab/openart in openart-tools/tool.hubspot_integration.5ebd51c72e954598/SKILL.md and read by ahel’s review.

Use this skill when the OpenART registry selects tool.hubspot_integration.5ebd51c72e954598 for the current task.

HubSpot Integration Patterns

Build reliable HubSpot ↔ Airtable sync workflows. This skill covers API selection, rate limits, sync architecture, and n8n implementation.

Quick Reference

TaskAPIEndpoint Pattern
CRUD objectsv3POST /crm/v3/objects/{type}
Search/filterv3POST /crm/v3/objects/{type}/search
Batch upsertv3POST /crm/v3/objects/{type}/batch/upsert
Associations (all)v4POST /crm/v4/associations/{from}/{to}/batch/read
Labeled associationsv4PUT /crm/v4/objects/{type}/{id}/associations/{toType}/{toId}

API Selection

Use v3 for Objects + Search

/crm/v3/objects/contacts          # CRUD
/crm/v3/objects/contacts/search   # Filter + paginate
/crm/v3/objects/contacts/batch/upsert  # Bulk writes

Use v4 for Associations

v3 associations only return the primary associated company. v4 returns all associations with labels.

/crm/v4/associations/contacts/companies/batch/read  # Batch read (1000 inputs)
/crm/v4/objects/contact/{id}/associations/company/{companyId}  # Labeled association

Authentication

Use Private App tokens (Bearer auth). API keys are deprecated.

Authorization: Bearer {ACCESS_TOKEN}

Required scopes for sync:

  • crm.objects.contacts.read / .write
  • crm.objects.companies.read / .write
  • crm.objects.deals.read / .write
  • crm.schemas.custom.read

Rate Limits

Tiered Limits (Private Apps)

TierBurst (per 10s)Daily
Free/Starter100250,000
Professional190625,000
Enterprise1901,000,000

Search API: Separate Limit

5 requests/second per token — no rate limit headers returned.

Associations API (v4)

  • Burst: 100-150/10s depending on tier
  • Batch read: 1,000 inputs max
  • Batch create: 2,000 inputs max

Rate Limit Headers

X-HubSpot-RateLimit-Remaining      # Requests left in 10s window
X-HubSpot-RateLimit-Daily-Remaining # Requests left today
Retry-After                        # Seconds to wait after 429

Backoff Strategy:

  1. If Retry-After header exists, wait that duration
  2. Otherwise, if X-HubSpot-RateLimit-Remaining < 10, wait 3 seconds
  3. On 429 without headers, wait 10 seconds (TEN_SECONDLY_ROLLING policy)

Sync Architecture

Recommended: Hybrid Pattern

  • Webhooks for immediacy (deletions, merges, critical updates)
  • Polling with watermark for completeness (incremental sync)

Watermark Incremental Sync (Read Path)

// Store watermark: last_sync_timestamp (epoch ms)
{
  "filterGroups": [{
    "filters": [{
      "propertyName": "lastmodifieddate",  // Note: NOT hs_lastmodifieddate for contacts
      "operator": "GT",
      "value": "1674758400000"
    }]
  }],
  "sorts": [{ "propertyName": "lastmodifieddate", "direction": "ASCENDING" }],
  "limit": 200,
  "after": "cursor_from_previous_page",
  "properties": ["email", "firstname", "lastname", "hs_object_id"]
}

Critical: Use overlap window (watermark minus 2-5 minutes) to avoid missing records with identical timestamps.

Write Path (Airtable → HubSpot)

Use batch upsert with idProperty for idempotent writes:

POST /crm/v3/objects/contacts/batch/upsert?idProperty=email
{
  "inputs": [
    { "id": "user@example.com", "properties": { "firstname": "James" } }
  ]
}

Avoiding N+1 Queries

Bad: Fetch 100 contacts, then 100 individual association calls = 101 requests

Good: Batch read associations:

POST /crm/v4/associations/contacts/companies/batch/read
{ "inputs": [{ "id": "101" }, { "id": "102" }, ...] }  // up to 1000

Bi-Directional Loop Prevention

Prevent infinite sync loops with:

  1. Field-level diffing: Only write if incoming value differs from existing
  2. "Last Updated By" filter: Exclude changes made by integration user
    hs_updated_by_user_id NOT_EQ {integration_user_id}
    

Reference Files

Signals

GitHub stars
228
Forks
21
Last commit
Oct 2026
Advanced
Item type
skill
Key
tool-hubspot-integration-5ebd51c72e954598
Source
github.com/ai45lab/openart