{"id":"daacb539-790f-4a80-802e-e0bf601086c2","shortId":"JKSTUN","kind":"skill","title":"hubspot-integration","tagline":"Expert patterns for HubSpot CRM integration including OAuth","description":"# HubSpot Integration\n\nExpert patterns for HubSpot CRM integration including OAuth authentication,\nCRM objects, associations, batch operations, webhooks, and custom objects.\nCovers Node.js and Python SDKs.\n\n## Patterns\n\n### OAuth 2.0 Authentication\n\nSecure authentication for public apps\n\n**When to use**: Building public app or multi-account integration\n\n### Template\n\n// OAuth 2.0 flow for HubSpot\nimport { Client } from \"@hubspot/api-client\";\n\n// Environment variables\nconst CLIENT_ID = process.env.HUBSPOT_CLIENT_ID;\nconst CLIENT_SECRET = process.env.HUBSPOT_CLIENT_SECRET;\nconst REDIRECT_URI = process.env.HUBSPOT_REDIRECT_URI;\nconst SCOPES = \"crm.objects.contacts.read crm.objects.contacts.write\";\n\n// Step 1: Generate authorization URL\nfunction getAuthUrl(): string {\n  const authUrl = new URL(\"https://app.hubspot.com/oauth/authorize\");\n  authUrl.searchParams.set(\"client_id\", CLIENT_ID);\n  authUrl.searchParams.set(\"redirect_uri\", REDIRECT_URI);\n  authUrl.searchParams.set(\"scope\", SCOPES);\n  return authUrl.toString();\n}\n\n// Step 2: Handle OAuth callback\nasync function handleOAuthCallback(code: string) {\n  const response = await fetch(\"https://api.hubapi.com/oauth/v1/token\", {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n    body: new URLSearchParams({\n      grant_type: \"authorization_code\",\n      client_id: CLIENT_ID,\n      client_secret: CLIENT_SECRET,\n      redirect_uri: REDIRECT_URI,\n      code: code,\n    }),\n  });\n\n  const tokens = await response.json();\n  // {\n  //   access_token: \"xxx\",\n  //   refresh_token: \"xxx\",\n  //   expires_in: 1800  // 30 minutes\n  // }\n\n  // Store tokens securely\n  await storeTokens(tokens);\n\n  return tokens;\n}\n\n// Step 3: Refresh access token (before expiry)\nasync function refreshAccessToken(refreshToken: string) {\n  const response = await fetch(\"https://api.hubapi.com/oauth/v1/token\", {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n    body: new URLSearchParams({\n      grant_type: \"refresh_token\",\n      client_id: CLIENT_ID,\n      client_secret: CLIENT_SECRET,\n      refresh_token: refreshToken,\n    }),\n  });\n\n  return response.json();\n}\n\n// Step 4: Create authenticated client\nfunction createClient(accessToken: string): Client {\n  const hubspotClient = new Client({ accessToken });\n  return hubspotClient;\n}\n\n### Notes\n\n- Access tokens expire in 30 minutes\n- Refresh tokens before expiry\n- Store refresh tokens securely\n- Rotate tokens every 6 months\n\n### Private App Token\n\nAuthentication for single-account integrations\n\n**When to use**: Building internal integration for one HubSpot account\n\n### Template\n\n// Private App Token - simpler for single account\nimport { Client } from \"@hubspot/api-client\";\n\n// Create client with private app token\nconst hubspotClient = new Client({\n  accessToken: process.env.HUBSPOT_PRIVATE_APP_TOKEN,\n});\n\n// Private app tokens don't expire\n// But should be rotated every 6 months for security\n\n// Example: Get contacts\nasync function getContacts() {\n  try {\n    const response = await hubspotClient.crm.contacts.basicApi.getPage(\n      100,  // limit\n      undefined,  // after cursor\n      [\"firstname\", \"lastname\", \"email\", \"phone\"],  // properties\n    );\n\n    return response.results;\n  } catch (error) {\n    if (error.code === 429) {\n      // Rate limited - implement backoff\n      const retryAfter = error.headers?.[\"retry-after\"] || 10;\n      await sleep(retryAfter * 1000);\n      return getContacts();\n    }\n    throw error;\n  }\n}\n\n// Python equivalent\n// from hubspot import HubSpot\n//\n// client = HubSpot(access_token=os.environ[\"HUBSPOT_PRIVATE_APP_TOKEN\"])\n//\n// contacts = client.crm.contacts.basic_api.get_page(\n//     limit=100,\n//     properties=[\"firstname\", \"lastname\", \"email\"]\n// )\n\n### Notes\n\n- Private app tokens don't expire\n- All private apps share daily rate limit\n- Each private app has own burst limit\n- Recommended: Rotate every 6 months\n\n### CRM Object CRUD Operations\n\nCreate, read, update, delete CRM records\n\n**When to use**: Working with contacts, companies, deals, tickets\n\n### Template\n\nimport { Client } from \"@hubspot/api-client\";\n\nconst hubspotClient = new Client({\n  accessToken: process.env.HUBSPOT_TOKEN,\n});\n\n// CREATE contact\nasync function createContact(data: {\n  email: string;\n  firstname: string;\n  lastname: string;\n}) {\n  const response = await hubspotClient.crm.contacts.basicApi.create({\n    properties: {\n      email: data.email,\n      firstname: data.firstname,\n      lastname: data.lastname,\n    },\n  });\n\n  return response;\n}\n\n// READ contact by ID\nasync function getContact(contactId: string) {\n  const response = await hubspotClient.crm.contacts.basicApi.getById(\n    contactId,\n    [\"firstname\", \"lastname\", \"email\", \"phone\", \"company\"],\n  );\n\n  return response;\n}\n\n// UPDATE contact\nasync function updateContact(contactId: string, properties: object) {\n  const response = await hubspotClient.crm.contacts.basicApi.update(\n    contactId,\n    { properties },\n  );\n\n  return response;\n}\n\n// DELETE contact\nasync function deleteContact(contactId: string) {\n  await hubspotClient.crm.contacts.basicApi.archive(contactId);\n}\n\n// SEARCH contacts\nasync function searchContacts(query: string) {\n  const response = await hubspotClient.crm.contacts.searchApi.doSearch({\n    query,\n    limit: 100,\n    properties: [\"firstname\", \"lastname\", \"email\"],\n    sorts: [{ propertyName: \"createdate\", direction: \"DESCENDING\" }],\n  });\n\n  return response.results;\n}\n\n// LIST with pagination\nasync function getAllContacts() {\n  const allContacts = [];\n  let after = undefined;\n\n  do {\n    const response = await hubspotClient.crm.contacts.basicApi.getPage(\n      100,\n      after,\n      [\"firstname\", \"lastname\", \"email\"],\n    );\n\n    allContacts.push(...response.results);\n    after = response.paging?.next?.after;\n  } while (after);\n\n  return allContacts;\n}\n\n### Notes\n\n- Use properties param to fetch only needed fields\n- Search API has 10k result limit\n- Always implement pagination for lists\n- Archive (soft delete) vs. GDPR delete available\n\n### Batch Operations\n\nBulk create, update, or read records efficiently\n\n**When to use**: Processing multiple records (reduce rate limit usage)\n\n### Template\n\nimport { Client } from \"@hubspot/api-client\";\n\nconst hubspotClient = new Client({\n  accessToken: process.env.HUBSPOT_TOKEN,\n});\n\n// BATCH CREATE contacts (up to 100 per batch)\nasync function batchCreateContacts(contacts: Array<{\n  email: string;\n  firstname: string;\n  lastname: string;\n}>) {\n  const inputs = contacts.map((contact) => ({\n    properties: {\n      email: contact.email,\n      firstname: contact.firstname,\n      lastname: contact.lastname,\n    },\n  }));\n\n  const response = await hubspotClient.crm.contacts.batchApi.create({\n    inputs,\n  });\n\n  return response.results;\n}\n\n// BATCH UPDATE contacts\nasync function batchUpdateContacts(\n  updates: Array<{ id: string; properties: object }>\n) {\n  const inputs = updates.map(({ id, properties }) => ({\n    id,\n    properties,\n  }));\n\n  const response = await hubspotClient.crm.contacts.batchApi.update({\n    inputs,\n  });\n\n  return response.results;\n}\n\n// BATCH READ contacts by ID\nasync function batchReadContacts(\n  ids: string[],\n  properties: string[] = [\"firstname\", \"lastname\", \"email\"]\n) {\n  const response = await hubspotClient.crm.contacts.batchApi.read({\n    inputs: ids.map((id) => ({ id })),\n    properties,\n  });\n\n  return response.results;\n}\n\n// BATCH ARCHIVE contacts\nasync function batchDeleteContacts(ids: string[]) {\n  await hubspotClient.crm.contacts.batchApi.archive({\n    inputs: ids.map((id) => ({ id })),\n  });\n}\n\n// Process large dataset in chunks\nasync function processLargeDataset(allContacts: any[]) {\n  const BATCH_SIZE = 100;\n  const results = [];\n\n  for (let i = 0; i < allContacts.length; i += BATCH_SIZE) {\n    const batch = allContacts.slice(i, i + BATCH_SIZE);\n    const batchResults = await batchCreateContacts(batch);\n    results.push(...batchResults);\n\n    // Respect rate limits - wait between batches\n    if (i + BATCH_SIZE < allContacts.length) {\n      await sleep(100);  // 100ms between batches\n    }\n  }\n\n  return results;\n}\n\n### Notes\n\n- Max 100 items per batch request\n- Saves up to 80% of rate limit quota\n- Batch operations are atomic per item (partial success possible)\n- Check response.errors for failed items\n\n### Associations v4 API\n\nCreate relationships between CRM records\n\n**When to use**: Linking contacts to companies, deals, etc.\n\n### Template\n\nimport { Client, AssociationTypes } from \"@hubspot/api-client\";\n\nconst hubspotClient = new Client({\n  accessToken: process.env.HUBSPOT_TOKEN,\n});\n\n// CREATE association (Contact to Company)\nasync function associateContactToCompany(\n  contactId: string,\n  companyId: string\n) {\n  await hubspotClient.crm.associations.v4.basicApi.create(\n    \"contacts\",\n    contactId,\n    \"companies\",\n    companyId,\n    [\n      {\n        associationCategory: \"HUBSPOT_DEFINED\",\n        associationTypeId: AssociationTypes.contactToCompany,\n      },\n    ]\n  );\n}\n\n// CREATE association (Deal to Contact)\nasync function associateDealToContact(dealId: string, contactId: string) {\n  await hubspotClient.crm.associations.v4.basicApi.create(\n    \"deals\",\n    dealId,\n    \"contacts\",\n    contactId,\n    [\n      {\n        associationCategory: \"HUBSPOT_DEFINED\",\n        associationTypeId: 3,  // deal_to_contact\n      },\n    ]\n  );\n}\n\n// GET associations for a record\nasync function getContactCompanies(contactId: string) {\n  const response = await hubspotClient.crm.associations.v4.basicApi.getPage(\n    \"contacts\",\n    contactId,\n    \"companies\",\n    undefined,\n    500\n  );\n\n  return response.results;\n}\n\n// CREATE association with custom label\nasync function createLabeledAssociation(\n  contactId: string,\n  companyId: string,\n  labelId: number  // Custom association label ID\n) {\n  await hubspotClient.crm.associations.v4.basicApi.create(\n    \"contacts\",\n    contactId,\n    \"companies\",\n    companyId,\n    [\n      {\n        associationCategory: \"USER_DEFINED\",\n        associationTypeId: labelId,\n      },\n    ]\n  );\n}\n\n// BATCH create associations\nasync function batchAssociateContactsToCompany(\n  contactIds: string[],\n  companyId: string\n) {\n  const inputs = contactIds.map((contactId) => ({\n    _from: { id: contactId },\n    to: { id: companyId },\n    types: [\n      {\n        associationCategory: \"HUBSPOT_DEFINED\",\n        associationTypeId: AssociationTypes.contactToCompany,\n      },\n    ],\n  }));\n\n  await hubspotClient.crm.associations.v4.batchApi.create(\n    \"contacts\",\n    \"companies\",\n    { inputs }\n  );\n}\n\n// Common association type IDs\n// Contact to Company: 1\n// Company to Contact: 2\n// Deal to Contact: 3\n// Contact to Deal: 4\n// Deal to Company: 5\n// Company to Deal: 6\n\n### Notes\n\n- Requires SDK version 9.0.0+ for v4 API\n- Association labels supported for custom relationships\n- Use batch API for multiple associations\n- HUBSPOT_DEFINED for standard, USER_DEFINED for custom labels\n\n### Webhook Handling\n\nReceive real-time notifications from HubSpot\n\n**When to use**: Need instant updates on CRM changes\n\n### Template\n\nimport crypto from \"crypto\";\nimport { Client } from \"@hubspot/api-client\";\n\n// Webhook signature validation\nfunction validateWebhookSignature(\n  requestBody: string,\n  signature: string,\n  clientSecret: string\n): boolean {\n  // For v2 signature (most common)\n  const expectedSignature = crypto\n    .createHmac(\"sha256\", clientSecret)\n    .update(requestBody)\n    .digest(\"hex\");\n\n  return signature === expectedSignature;\n}\n\n// Express webhook handler\napp.post(\"/webhooks/hubspot\", async (req, res) => {\n  const signature = req.headers[\"x-hubspot-signature-v3\"] as string;\n  const timestamp = req.headers[\"x-hubspot-request-timestamp\"] as string;\n  const requestBody = JSON.stringify(req.body);\n\n  // Validate signature\n  const isValid = validateWebhookSignature(\n    requestBody,\n    signature,\n    process.env.HUBSPOT_CLIENT_SECRET\n  );\n\n  if (!isValid) {\n    console.error(\"Invalid webhook signature\");\n    return res.status(401).send(\"Unauthorized\");\n  }\n\n  // Check timestamp (prevent replay attacks)\n  const timestampAge = Date.now() - parseInt(timestamp);\n  if (timestampAge > 300000) {  // 5 minutes\n    console.error(\"Webhook timestamp too old\");\n    return res.status(401).send(\"Timestamp expired\");\n  }\n\n  // Process events - respond quickly!\n  const events = req.body;\n\n  // Queue for async processing\n  for (const event of events) {\n    await queue.add(\"hubspot-webhook\", event);\n  }\n\n  // Respond immediately\n  res.status(200).send(\"OK\");\n});\n\n// Async processor\nasync function processWebhookEvent(event: any) {\n  const { subscriptionType, objectId, propertyName, propertyValue } = event;\n\n  switch (subscriptionType) {\n    case \"contact.creation\":\n      await handleContactCreated(objectId);\n      break;\n\n    case \"contact.propertyChange\":\n      await handleContactPropertyChange(objectId, propertyName, propertyValue);\n      break;\n\n    case \"deal.creation\":\n      await handleDealCreated(objectId);\n      break;\n\n    case \"contact.deletion\":\n      await handleContactDeleted(objectId);\n      break;\n\n    default:\n      console.log(`Unhandled event: ${subscriptionType}`);\n  }\n}\n\n// Webhook subscription types:\n// contact.creation, contact.deletion, contact.propertyChange\n// company.creation, company.deletion, company.propertyChange\n// deal.creation, deal.deletion, deal.propertyChange\n\n### Notes\n\n- Validate signature before processing\n- Respond within 5 seconds\n- Queue heavy processing for async\n- Max 1000 webhook subscriptions per app\n\n### Custom Objects\n\nCreate and manage custom object types\n\n**When to use**: Standard objects don't fit your data model\n\n### Template\n\nimport { Client } from \"@hubspot/api-client\";\n\nconst hubspotClient = new Client({\n  accessToken: process.env.HUBSPOT_TOKEN,\n});\n\n// CREATE custom object schema\nasync function createCustomObjectSchema() {\n  const schema = {\n    name: \"projects\",\n    labels: {\n      singular: \"Project\",\n      plural: \"Projects\",\n    },\n    primaryDisplayProperty: \"project_name\",\n    requiredProperties: [\"project_name\"],\n    properties: [\n      {\n        name: \"project_name\",\n        label: \"Project Name\",\n        type: \"string\",\n        fieldType: \"text\",\n      },\n      {\n        name: \"status\",\n        label: \"Status\",\n        type: \"enumeration\",\n        fieldType: \"select\",\n        options: [\n          { label: \"Active\", value: \"active\" },\n          { label: \"Completed\", value: \"completed\" },\n          { label: \"On Hold\", value: \"on_hold\" },\n        ],\n      },\n      {\n        name: \"budget\",\n        label: \"Budget\",\n        type: \"number\",\n        fieldType: \"number\",\n      },\n      {\n        name: \"start_date\",\n        label: \"Start Date\",\n        type: \"date\",\n        fieldType: \"date\",\n      },\n    ],\n    associatedObjects: [\"CONTACT\", \"COMPANY\"],\n  };\n\n  const response = await hubspotClient.crm.schemas.coreApi.create(schema);\n  return response;\n}\n\n// CREATE custom object record\nasync function createProject(data: {\n  project_name: string;\n  status: string;\n  budget: number;\n}) {\n  const response = await hubspotClient.crm.objects.basicApi.create(\n    \"projects\",  // Custom object name\n    { properties: data }\n  );\n\n  return response;\n}\n\n// READ custom object by ID\nasync function getProject(projectId: string) {\n  const response = await hubspotClient.crm.objects.basicApi.getById(\n    \"projects\",\n    projectId,\n    [\"project_name\", \"status\", \"budget\", \"start_date\"]\n  );\n\n  return response;\n}\n\n// UPDATE custom object\nasync function updateProject(projectId: string, properties: object) {\n  const response = await hubspotClient.crm.objects.basicApi.update(\n    \"projects\",\n    projectId,\n    { properties }\n  );\n\n  return response;\n}\n\n// SEARCH custom objects\nasync function searchProjects(status: string) {\n  const response = await hubspotClient.crm.objects.searchApi.doSearch(\n    \"projects\",\n    {\n      filterGroups: [\n        {\n          filters: [\n            {\n              propertyName: \"status\",\n              operator: \"EQ\",\n              value: status,\n            },\n          ],\n        },\n      ],\n      properties: [\"project_name\", \"status\", \"budget\"],\n      limit: 100,\n    }\n  );\n\n  return response.results;\n}\n\n### Notes\n\n- Custom objects require Enterprise tier\n- Max 10 custom objects per account\n- Use crm.objects API with object name as parameter\n- Can associate with standard and other custom objects\n\n## Sharp Edges\n\n### Rate Limits Vary by App Type and Hub Tier\n\nSeverity: HIGH\n\n### 5% Error Rate Threshold for Marketplace Apps\n\nSeverity: HIGH\n\n### API Keys Deprecated - Use OAuth or Private App Tokens\n\nSeverity: CRITICAL\n\n### OAuth Access Tokens Expire in 30 Minutes\n\nSeverity: HIGH\n\n### Webhook Requests Must Be Validated\n\nSeverity: CRITICAL\n\n### All List Endpoints Require Pagination\n\nSeverity: MEDIUM\n\n### Associations v4 API Has Breaking Changes\n\nSeverity: HIGH\n\n### Polling Limited to 100,000 Requests Per Day\n\nSeverity: MEDIUM\n\n## Validation Checks\n\n### Hardcoded HubSpot API Key\n\nSeverity: ERROR\n\nAPI keys must never be hardcoded\n\nMessage: Hardcoded HubSpot API key detected. Use environment variables. Note: API keys are deprecated - use Private App tokens.\n\n### Hardcoded HubSpot Access Token\n\nSeverity: ERROR\n\nAccess tokens must use environment variables\n\nMessage: Hardcoded HubSpot access token. Use environment variables.\n\n### Hardcoded Client Secret\n\nSeverity: ERROR\n\nOAuth client secrets must be secured\n\nMessage: Hardcoded client secret. Use environment variables.\n\n### Missing Webhook Signature Validation\n\nSeverity: ERROR\n\nWebhook endpoints must validate HubSpot signatures\n\nMessage: Webhook endpoint without signature validation. Validate X-HubSpot-Signature-v3.\n\n### Missing Rate Limit Handling\n\nSeverity: WARNING\n\nAPI calls should handle 429 responses\n\nMessage: HubSpot API calls without rate limit handling. Implement retry logic with backoff.\n\n### Unthrottled Parallel API Calls\n\nSeverity: WARNING\n\nParallel calls can exceed rate limits\n\nMessage: Parallel HubSpot API calls without throttling. Use rate limiter.\n\n### Missing Pagination for List Calls\n\nSeverity: WARNING\n\nList endpoints return paginated results\n\nMessage: API call without pagination handling. Implement cursor-based pagination.\n\n### Individual Operations in Loop\n\nSeverity: INFO\n\nUse batch operations for multiple items\n\nMessage: Individual API calls in loop. Consider batch operations for better performance.\n\n### Token Storage Without Expiry\n\nSeverity: WARNING\n\nOAuth tokens expire and need refresh logic\n\nMessage: Token storage without expiry tracking. Store expiresAt for refresh logic.\n\n### Deprecated API Key Usage\n\nSeverity: ERROR\n\nAPI keys are deprecated\n\nMessage: Using deprecated API key. Migrate to Private App token or OAuth 2.0.\n\n## Collaboration\n\n### Delegation Triggers\n\n- user needs email marketing automation -> email-marketing (Beyond HubSpot's built-in email tools)\n- user needs custom CRM UI -> frontend (Building portal or dashboard)\n- user needs data pipeline -> data-engineer (ETL from HubSpot to warehouse)\n- user needs Salesforce integration -> salesforce-development (HubSpot + Salesforce sync)\n- user needs payment processing -> stripe-integration (Payments beyond HubSpot quotes)\n- user needs analytics dashboard -> analytics-specialist (Custom reporting beyond HubSpot)\n\n## When to Use\n- User mentions or implies: hubspot\n- User mentions or implies: hubspot api\n- User mentions or implies: hubspot crm\n- User mentions or implies: hubspot integration\n- User mentions or implies: contacts api\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["hubspot","integration","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows"],"capabilities":["skill","source-sickn33","skill-hubspot-integration","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/hubspot-integration","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34768 github stars · SKILL.md body (19,876 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-23T18:51:28.943Z","embedding":null,"createdAt":"2026-04-18T21:38:41.430Z","updatedAt":"2026-04-23T18:51:28.943Z","lastSeenAt":"2026-04-23T18:51:28.943Z","tsv":"'/oauth/authorize':105 '/oauth/v1/token':137,207 '/webhooks/hubspot':1116 '0':770 '000':1608 '1':92,1005 '10':371,1519 '100':344,399,547,575,653,764,803,811,1509,1607 '1000':375,1292 '100ms':804 '10k':602 '1800':178 '2':122,1009 '2.0':39,59,1848 '200':1216 '3':190,913,1013 '30':179,257,1578 '300000':1177 '4':236,1017 '401':1162,1187 '429':360,1718 '5':1021,1178,1284,1553 '500':935 '6':270,329,428,1025 '80':819 '9.0.0':1030 'access':170,192,253,388,1574,1648,1652,1661 'accesstoken':242,249,313,458,645,865,1325 'account':55,279,290,298,1523 'activ':1371,1373 'allcontact':566,589,759 'allcontacts.length':772,800 'allcontacts.push':580 'allcontacts.slice':778 'alway':605 'analyt':1913,1916 'analytics-specialist':1915 'api':600,840,1033,1042,1526,1562,1598,1618,1622,1631,1638,1714,1722,1735,1748,1768,1792,1827,1832,1839,1935,1953 'api.hubapi.com':136,206 'api.hubapi.com/oauth/v1/token':135,205 'app':45,51,273,293,307,316,319,393,406,413,420,1296,1546,1559,1569,1644,1844 'app.hubspot.com':104 'app.hubspot.com/oauth/authorize':103 'app.post':1115 'application/x-www-form-urlencoded':144,214 'archiv':610,738 'array':660,692 'ask':1987 'associ':25,838,869,892,918,939,953,969,999,1034,1045,1533,1596 'associatecontacttocompani':875 'associatedealtocontact':898 'associatedobject':1402 'associationcategori':886,909,962,988 'associationtyp':858 'associationtypeid':889,912,965,991 'associationtypes.contacttocompany':890,992 'async':126,196,336,463,490,509,526,536,562,656,688,716,740,756,873,896,922,943,970,1117,1200,1219,1221,1290,1332,1416,1444,1466,1485 'atom':827 'attack':1169 'authent':22,40,42,238,275 'author':94,150 'authurl':100 'authurl.searchparams.set':106,111,116 'authurl.tostring':120 'autom':1856 'avail':616 'await':133,168,184,203,342,372,475,497,518,531,543,573,680,706,728,745,785,801,880,903,929,956,993,1207,1236,1242,1250,1256,1407,1429,1451,1475,1492 'backoff':364,1732 'base':1776 'batch':26,617,648,655,685,711,737,762,774,777,781,787,795,798,806,814,824,967,1041,1785,1797 'batchassociatecontactstocompani':972 'batchcreatecontact':658,786 'batchdeletecontact':742 'batchreadcontact':718 'batchresult':784,789 'batchupdatecontact':690 'better':1800 'beyond':1860,1908,1920 'bodi':145,215 'boolean':1093 'boundari':1995 'break':1239,1247,1253,1259,1600 'budget':1385,1387,1425,1458,1507 'build':49,284,1874 'built':1864 'built-in':1863 'bulk':619 'burst':423 'call':1715,1723,1736,1740,1749,1759,1769,1793 'callback':125 'case':1234,1240,1248,1254 'catch':356 'chang':1072,1601 'check':833,1165,1615 'chunk':755 'clarif':1989 'clear':1962 'client':64,70,73,76,79,107,109,152,154,156,158,222,224,226,228,239,244,248,300,304,312,386,451,457,638,644,857,864,1079,1152,1318,1324,1667,1672,1679 'client.crm.contacts.basic_api.get':396 'clientsecret':1091,1104 'code':129,151,164,165 'collabor':1849 'common':998,1098 'compani':446,504,852,872,884,933,960,996,1004,1006,1020,1022,1404 'company.creation':1271 'company.deletion':1272 'company.propertychange':1273 'companyid':878,885,948,961,975,986 'complet':1375,1377 'consid':1796 'console.error':1156,1180 'console.log':1261 'const':69,75,81,87,99,131,166,201,245,309,340,365,454,473,495,516,541,565,571,641,667,678,697,704,726,761,765,776,783,861,927,977,1099,1120,1130,1140,1146,1170,1195,1203,1226,1321,1335,1405,1427,1449,1473,1490 'contact':335,395,445,462,487,508,525,535,650,659,670,687,713,739,850,870,882,895,907,916,931,958,995,1002,1008,1012,1014,1403,1952 'contact.creation':1235,1268 'contact.deletion':1255,1269 'contact.email':673 'contact.firstname':675 'contact.lastname':677 'contact.propertychange':1241,1270 'contactid':493,499,512,520,529,533,876,883,901,908,925,932,946,959,973,980,983 'contactids.map':979 'contacts.map':669 'content':142,212 'content-typ':141,211 'cover':32 'creat':237,303,434,461,620,649,841,868,891,938,968,1299,1328,1412 'createcli':241 'createcontact':465 'createcustomobjectschema':1334 'created':554 'createhmac':1102 'createlabeledassoci':945 'createproject':1418 'criteria':1998 'critic':1572,1588 'crm':8,18,23,430,438,844,1071,1871,1941 'crm.objects':1525 'crm.objects.contacts.read':89 'crm.objects.contacts.write':90 'crud':432 'crypto':1075,1077,1101 'cursor':348,1775 'cursor-bas':1774 'custom':30,941,952,1038,1053,1297,1302,1329,1413,1432,1440,1464,1483,1513,1520,1538,1870,1918 'daili':415 'dashboard':1877,1914 'data':466,1314,1419,1436,1880,1883 'data-engin':1882 'data.email':479 'data.firstname':481 'data.lastname':483 'dataset':753 'date':1394,1397,1399,1401,1460 'date.now':1172 'day':1611 'deal':447,853,893,905,914,1010,1016,1018,1024 'deal.creation':1249,1274 'deal.deletion':1275 'deal.propertychange':1276 'dealid':899,906 'default':1260 'defin':888,911,964,990,1047,1051 'deleg':1850 'delet':437,524,612,615 'deletecontact':528 'deprec':1564,1641,1826,1835,1838 'descend':556 'describ':1966 'detect':1633 'develop':1896 'digest':1107 'direct':555 'edg':1541 'effici':625 'email':351,403,467,478,502,551,579,661,672,725,1854,1858,1866 'email-market':1857 'endpoint':1591,1691,1698,1763 'engin':1884 'enterpris':1516 'enumer':1366 'environ':67,1635,1656,1664,1682,1978 'environment-specif':1977 'eq':1500 'equival':381 'error':357,379,1554,1621,1651,1670,1689,1831 'error.code':359 'error.headers':367 'etc':854 'etl':1885 'event':1192,1196,1204,1206,1212,1224,1231,1263 'everi':269,328,427 'exampl':333 'exceed':1742 'expectedsignatur':1100,1111 'expert':4,14,1983 'expir':176,255,323,410,1190,1576,1810 'expiresat':1822 'expiri':195,262,1805,1819 'express':1112 'fail':836 'fetch':134,204,595 'field':598 'fieldtyp':1359,1367,1390,1400 'filter':1496 'filtergroup':1495 'firstnam':349,401,469,480,500,549,577,663,674,723 'fit':1312 'flow':60 'frontend':1873 'function':96,127,197,240,337,464,491,510,527,537,563,657,689,717,741,757,874,897,923,944,971,1085,1222,1333,1417,1445,1467,1486 'gdpr':614 'generat':93 'get':334,917 'getallcontact':564 'getauthurl':97 'getcontact':338,377,492 'getcontactcompani':924 'getproject':1446 'grant':148,218 'handl':123,1056,1711,1717,1727,1772 'handlecontactcr':1237 'handlecontactdelet':1257 'handlecontactpropertychang':1243 'handledealcr':1251 'handleoauthcallback':128 'handler':1114 'hardcod':1616,1627,1629,1646,1659,1666,1678 'header':140,210 'heavi':1287 'hex':1108 'high':1552,1561,1581,1603 'hold':1380,1383 'hub':1549 'hubspot':2,7,12,17,62,289,383,385,387,391,887,910,989,1046,1063,1125,1135,1210,1617,1630,1647,1660,1694,1705,1721,1747,1861,1887,1897,1909,1921,1929,1934,1940,1946 'hubspot-integr':1 'hubspot-webhook':1209 'hubspot/api-client':66,302,453,640,860,1081,1320 'hubspotcli':246,251,310,455,642,862,1322 'hubspotclient.crm.associations.v4.basicapi.create':881,904,957 'hubspotclient.crm.associations.v4.basicapi.getpage':930 'hubspotclient.crm.associations.v4.batchapi.create':994 'hubspotclient.crm.contacts.basicapi.archive':532 'hubspotclient.crm.contacts.basicapi.create':476 'hubspotclient.crm.contacts.basicapi.getbyid':498 'hubspotclient.crm.contacts.basicapi.getpage':343,574 'hubspotclient.crm.contacts.basicapi.update':519 'hubspotclient.crm.contacts.batchapi.archive':746 'hubspotclient.crm.contacts.batchapi.create':681 'hubspotclient.crm.contacts.batchapi.read':729 'hubspotclient.crm.contacts.batchapi.update':707 'hubspotclient.crm.contacts.searchapi.dosearch':544 'hubspotclient.crm.objects.basicapi.create':1430 'hubspotclient.crm.objects.basicapi.getbyid':1452 'hubspotclient.crm.objects.basicapi.update':1476 'hubspotclient.crm.objects.searchapi.dosearch':1493 'hubspotclient.crm.schemas.coreapi.create':1408 'id':71,74,108,110,153,155,223,225,489,693,700,702,715,719,732,733,743,749,750,955,982,985,1001,1443 'ids.map':731,748 'immedi':1214 'implement':363,606,1728,1773 'impli':1928,1933,1939,1945,1951 'import':63,299,384,450,637,856,1074,1078,1317 'includ':10,20 'individu':1778,1791 'info':1783 'input':668,682,698,708,730,747,978,997,1992 'instant':1068 'integr':3,9,13,19,56,280,286,1893,1906,1947 'intern':285 'invalid':1157 'isvalid':1147,1155 'item':812,829,837,1789 'json.stringify':1142 'key':1563,1619,1623,1632,1639,1828,1833,1840 'label':942,954,1035,1054,1339,1354,1363,1370,1374,1378,1386,1395 'labelid':950,966 'larg':752 'lastnam':350,402,471,482,501,550,578,665,676,724 'let':567,768 'limit':345,362,398,417,424,546,604,634,792,822,1508,1543,1605,1710,1726,1744,1754,1954 'link':849 'list':559,609,1590,1758,1762 'logic':1730,1814,1825 'loop':1781,1795 'manag':1301 'market':1855,1859 'marketplac':1558 'match':1963 'max':810,1291,1518 'medium':1595,1613 'mention':1926,1931,1937,1943,1949 'messag':1628,1658,1677,1696,1720,1745,1767,1790,1815,1836 'method':138,208 'migrat':1841 'minut':180,258,1179,1579 'miss':1684,1708,1755,2000 'model':1315 'month':271,330,429 'multi':54 'multi-account':53 'multipl':630,1044,1788 'must':1584,1624,1654,1674,1692 'name':1337,1346,1349,1351,1353,1356,1361,1384,1392,1421,1434,1456,1505,1529 'need':597,1067,1812,1853,1869,1879,1891,1901,1912 'never':1625 'new':101,146,216,247,311,456,643,863,1323 'next':584 'node.js':33 'note':252,404,590,809,1026,1277,1512,1637 'notif':1061 'number':951,1389,1391,1426 'oauth':11,21,38,58,124,1566,1573,1671,1808,1847 'object':24,31,431,515,696,1298,1303,1309,1330,1414,1433,1441,1465,1472,1484,1514,1521,1528,1539 'objectid':1228,1238,1244,1252,1258 'ok':1218 'old':1184 'one':288 'oper':27,433,618,825,1499,1779,1786,1798 'option':1369 'os.environ':390 'output':1972 'page':397 'pagin':561,607,1593,1756,1765,1771,1777 'parallel':1734,1739,1746 'param':593 'paramet':1531 'parseint':1173 'partial':830 'pattern':5,15,37 'payment':1902,1907 'per':654,813,828,1295,1522,1610 'perform':1801 'permiss':1993 'phone':352,503 'pipelin':1881 'plural':1342 'poll':1604 'portal':1875 'possibl':832 'post':139,209 'prevent':1167 'primarydisplayproperti':1344 'privat':272,292,306,315,318,392,405,412,419,1568,1643,1843 'process':629,751,1191,1201,1281,1288,1903 'process.env.hubspot':72,78,84,314,459,646,866,1151,1326 'processlargedataset':758 'processor':1220 'processwebhookev':1223 'project':1338,1341,1343,1345,1348,1352,1355,1420,1431,1453,1455,1477,1494,1504 'projectid':1447,1454,1469,1478 'properti':353,400,477,514,521,548,592,671,695,701,703,721,734,1350,1435,1471,1479,1503 'propertynam':553,1229,1245,1497 'propertyvalu':1230,1246 'public':44,50 'python':35,380 'queri':539,545 'queue':1198,1286 'queue.add':1208 'quick':1194 'quot':1910 'quota':823 'rate':361,416,633,791,821,1542,1555,1709,1725,1743,1753 'read':435,486,623,712,1439 'real':1059 'real-tim':1058 'receiv':1057 'recommend':425 'record':439,624,631,845,921,1415 'redirect':82,85,112,114,160,162 'reduc':632 'refresh':173,191,220,230,259,264,1813,1824 'refreshaccesstoken':198 'refreshtoken':199,232 'relationship':842,1039 'replay':1168 'report':1919 'req':1118 'req.body':1143,1197 'req.headers':1122,1132 'request':815,1136,1583,1609 'requestbodi':1087,1106,1141,1149 'requir':1027,1515,1592,1991 'requiredproperti':1347 'res':1119 'res.status':1161,1186,1215 'respect':790 'respond':1193,1213,1282 'respons':132,202,341,474,485,496,506,517,523,542,572,679,705,727,928,1406,1411,1428,1438,1450,1462,1474,1481,1491,1719 'response.errors':834 'response.json':169,234 'response.paging':583 'response.results':355,558,581,684,710,736,937,1511 'result':603,766,808,1766 'results.push':788 'retri':369,1729 'retry-aft':368 'retryaft':366,374 'return':119,187,233,250,354,376,484,505,522,557,588,683,709,735,807,936,1109,1160,1185,1410,1437,1461,1480,1510,1764 'review':1984 'rotat':267,327,426 'safeti':1994 'salesforc':1892,1895,1898 'salesforce-develop':1894 'save':816 'schema':1331,1336,1409 'scope':88,117,118,1965 'sdk':1028 'sdks':36 'search':534,599,1482 'searchcontact':538 'searchproject':1487 'second':1285 'secret':77,80,157,159,227,229,1153,1668,1673,1680 'secur':41,183,266,332,1676 'select':1368 'send':1163,1188,1217 'sever':1551,1560,1571,1580,1587,1594,1602,1612,1620,1650,1669,1688,1712,1737,1760,1782,1806,1830 'sha256':1103 'share':414 'sharp':1540 'signatur':1083,1089,1096,1110,1121,1126,1145,1150,1159,1279,1686,1695,1700,1706 'simpler':295 'singl':278,297 'single-account':277 'singular':1340 'size':763,775,782,799 'skill':1957 'skill-hubspot-integration' 'sleep':373,802 'soft':611 'sort':552 'source-sickn33' 'specialist':1917 'specif':1979 'standard':1049,1308,1535 'start':1393,1396,1459 'status':1362,1364,1423,1457,1488,1498,1502,1506 'step':91,121,189,235 'stop':1985 'storag':1803,1817 'store':181,263,1821 'storetoken':185 'string':98,130,200,243,468,470,472,494,513,530,540,662,664,666,694,720,722,744,877,879,900,902,926,947,949,974,976,1088,1090,1092,1129,1139,1358,1422,1424,1448,1470,1489 'stripe':1905 'stripe-integr':1904 'subscript':1266,1294 'subscriptiontyp':1227,1233,1264 'substitut':1975 'success':831,1997 'support':1036 'switch':1232 'sync':1899 'task':1961 'templat':57,291,449,636,855,1073,1316 'test':1981 'text':1360 'threshold':1556 'throttl':1751 'throw':378 'ticket':448 'tier':1517,1550 'time':1060 'timestamp':1131,1137,1166,1174,1182,1189 'timestampag':1171,1176 'token':167,171,174,182,186,188,193,221,231,254,260,265,268,274,294,308,317,320,389,394,407,460,647,867,1327,1570,1575,1645,1649,1653,1662,1802,1809,1816,1845 'tool':1867 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'track':1820 'treat':1970 'tri':339 'trigger':1851 'type':143,149,213,219,987,1000,1267,1304,1357,1365,1388,1398,1547 'ui':1872 'unauthor':1164 'undefin':346,569,934 'unhandl':1262 'unthrottl':1733 'updat':436,507,621,686,691,1069,1105,1463 'updatecontact':511 'updateproject':1468 'updates.map':699 'uri':83,86,113,115,161,163 'url':95,102 'urlsearchparam':147,217 'usag':635,1829 'use':48,283,442,591,628,848,1040,1066,1307,1524,1565,1634,1642,1655,1663,1681,1752,1784,1837,1924,1955 'user':963,1050,1852,1868,1878,1890,1900,1911,1925,1930,1936,1942,1948 'v2':1095 'v3':1127,1707 'v4':839,1032,1597 'valid':1084,1144,1278,1586,1614,1687,1693,1701,1702,1980 'validatewebhooksignatur':1086,1148 'valu':1372,1376,1381,1501 'vari':1544 'variabl':68,1636,1657,1665,1683 'version':1029 'vs':613 'wait':793 'warehous':1889 'warn':1713,1738,1761,1807 'webhook':28,1055,1082,1113,1158,1181,1211,1265,1293,1582,1685,1690,1697 'within':1283 'without':1699,1724,1750,1770,1804,1818 'work':443 'x':1124,1134,1704 'x-hubspot-request-timestamp':1133 'x-hubspot-signature-v3':1123,1703 'xxx':172,175","prices":[{"id":"7f11ec94-5a9c-4a09-89d6-678a6fbc82ee","listingId":"daacb539-790f-4a80-802e-e0bf601086c2","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:38:41.430Z"}],"sources":[{"listingId":"daacb539-790f-4a80-802e-e0bf601086c2","source":"github","sourceId":"sickn33/antigravity-awesome-skills/hubspot-integration","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/hubspot-integration","isPrimary":false,"firstSeenAt":"2026-04-18T21:38:41.430Z","lastSeenAt":"2026-04-23T18:51:28.943Z"}],"details":{"listingId":"daacb539-790f-4a80-802e-e0bf601086c2","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"hubspot-integration","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34768,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-23T06:41:03Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"277d8e9fb57428f07ad398cb9d1de71f2a470524","skill_md_path":"skills/hubspot-integration/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/hubspot-integration"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"hubspot-integration","description":"Expert patterns for HubSpot CRM integration including OAuth"},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/hubspot-integration"},"updatedAt":"2026-04-23T18:51:28.943Z"}}