Claude-code-plugins-plus hubspot-hello-world

install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/hubspot-pack/skills/hubspot-hello-world" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-hubspot-hello-world && rm -rf "$T"
manifest: plugins/saas-packs/hubspot-pack/skills/hubspot-hello-world/SKILL.md
source content

HubSpot Hello World

Overview

Create, read, update, and delete CRM records using the HubSpot API. Covers contacts, companies, and deals with real endpoints and SDK methods.

Prerequisites

  • Completed
    hubspot-install-auth
    setup
  • Private app with scopes:
    crm.objects.contacts.read
    ,
    crm.objects.contacts.write
  • @hubspot/api-client
    installed

Instructions

Step 1: Create a Contact

import * as hubspot from '@hubspot/api-client';

const client = new hubspot.Client({
  accessToken: process.env.HUBSPOT_ACCESS_TOKEN!,
});

// POST /crm/v3/objects/contacts
const contactResponse = await client.crm.contacts.basicApi.create({
  properties: {
    firstname: 'Jane',
    lastname: 'Doe',
    email: 'jane.doe@example.com',
    phone: '(555) 123-4567',
    company: 'Acme Corp',
    lifecyclestage: 'lead',
  },
  associations: [],
});

console.log(`Created contact: ${contactResponse.id}`);
// Output: Created contact: 12345

Step 2: Read a Contact

// GET /crm/v3/objects/contacts/{contactId}
const contact = await client.crm.contacts.basicApi.getById(
  contactResponse.id,
  ['firstname', 'lastname', 'email', 'phone', 'lifecyclestage'],
  undefined, // propertiesWithHistory
  ['companies'] // associations to include
);

console.log(`${contact.properties.firstname} ${contact.properties.lastname}`);
console.log(`Email: ${contact.properties.email}`);
console.log(`Stage: ${contact.properties.lifecyclestage}`);

Step 3: Update a Contact

// PATCH /crm/v3/objects/contacts/{contactId}
const updated = await client.crm.contacts.basicApi.update(
  contactResponse.id,
  {
    properties: {
      lifecyclestage: 'marketingqualifiedlead',
      phone: '(555) 987-6543',
    },
  }
);

console.log(`Updated at: ${updated.updatedAt}`);

Step 4: Create a Company and Associate

// POST /crm/v3/objects/companies
const company = await client.crm.companies.basicApi.create({
  properties: {
    name: 'Acme Corp',
    domain: 'acme.com',
    industry: 'TECHNOLOGY',
    numberofemployees: '150',
    annualrevenue: '5000000',
  },
  associations: [],
});

// Associate contact with company
// PUT /crm/v4/objects/contacts/{contactId}/associations/companies/{companyId}
await client.crm.associations.v4.basicApi.create(
  'contacts',
  contactResponse.id,
  'companies',
  company.id,
  [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 1 }]
);

console.log(`Associated contact ${contactResponse.id} with company ${company.id}`);

Step 5: Create a Deal

// POST /crm/v3/objects/deals
const deal = await client.crm.deals.basicApi.create({
  properties: {
    dealname: 'Acme Enterprise License',
    amount: '50000',
    dealstage: 'appointmentscheduled', // default pipeline stage ID
    pipeline: 'default',
    closedate: '2026-06-30T00:00:00.000Z',
    hubspot_owner_id: '12345', // owner user ID
  },
  associations: [
    {
      to: { id: company.id },
      types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 5 }],
    },
    {
      to: { id: contactResponse.id },
      types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 3 }],
    },
  ],
});

console.log(`Created deal: ${deal.properties.dealname} ($${deal.properties.amount})`);

Output

  • Created contact with properties and lifecycle stage
  • Read contact with specific properties and associations
  • Updated contact properties
  • Created company and associated it with the contact
  • Created deal associated with both contact and company

Error Handling

ErrorCodeCauseSolution
409 Conflict
409Contact with email already existsUse
crm.contacts.basicApi.getById
or search first
400 Bad Request
400Invalid property name or valueCheck property names in Settings > Properties
404 Not Found
404Record ID doesn't existVerify ID or check if archived
PROPERTY_DOESNT_EXIST
400Custom property not createdCreate in Settings > Properties first

Examples

Search for Existing Contacts

// POST /crm/v3/objects/contacts/search
const searchResults = await client.crm.contacts.searchApi.doSearch({
  filterGroups: [
    {
      filters: [
        {
          propertyName: 'email',
          operator: 'EQ',
          value: 'jane.doe@example.com',
        },
      ],
    },
  ],
  properties: ['firstname', 'lastname', 'email'],
  limit: 10,
  after: 0,
  sorts: [{ propertyName: 'createdate', direction: 'DESCENDING' }],
});

console.log(`Found ${searchResults.total} contact(s)`);

Delete (Archive) a Record

// DELETE /crm/v3/objects/contacts/{contactId}
await client.crm.contacts.basicApi.archive(contactResponse.id);
console.log('Contact archived');

Resources

Next Steps

Proceed to

hubspot-local-dev-loop
for development workflow setup.