smithery/ScientiaCapital

crm-integration

CRM integration patterns for Close CRM, HubSpot, and Salesforce. Use when: Close CRM, HubSpot, Salesforce, CRM API, lead sync, deal sync, activity logging, CRM webhook, pipeline automation, contact enrichment.

Installation

$ npx skills add smithery/ScientiaCapital --skill crm-integration

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/ScientiaCapital.

npx skills add smithery/ScientiaCapital

Browse all from smithery/ScientiaCapital

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 15,167 B
  • docs SUMMARY.md 232 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

<objective> Integrate with CRM platforms for sales automation workflows:

  1. Close CRM - Daily driver for SMB sales (simplest API, best value)
  2. HubSpot - Marketing + Sales alignment with rich ecosystem
  3. Salesforce - Enterprise requirements and complex workflows
  4. Cross-CRM Sync - Bidirectional sync with conflict resolution

Key deliverables:

  • API client setup with proper authentication
  • CRUD operations for leads, contacts, deals, activities
  • Webhook handlers for real-time sync
  • Pipeline automation and reporting

</objective>

<quick_start> Close CRM (API Key Auth):

import httpx

class CloseClient:
    BASE_URL = "https://api.close.com/api/v1"

    def __init__(self, api_key: str):
        self.client = httpx.Client(
            base_url=self.BASE_URL,
            auth=(api_key, ""),  # Basic auth, password empty
            timeout=30.0,
        )

    def create_lead(self, data: dict) -> dict:
        response = self.client.post("/lead/", json=data)
        response.raise_for_status()
        return response.json()

    def search_leads(self, query: str) -> list:
        response = self.client.post("/data/search/", json={
            "query": {"type": "query_string", "value": query},
            "results_limit": 100
        })
        return response.json()["data"]

# Usage
close = CloseClient(os.environ["CLOSE_API_KEY"])
leads = close.search_leads("company:Coperniq")

HubSpot (Python SDK):

from hubspot import HubSpot
from hubspot.crm.contacts import SimplePublicObjectInputForCreate

client = HubSpot(access_token=os.environ["HUBSPOT_ACCESS_TOKEN"])

# Create contact
contact = client.crm.contacts.basic_api.create(
    SimplePublicObjectInputForCreate(properties={
        "email": "[email protected]",
        "firstname": "Jane",
        "lastname": "Smith"
    })
)
print(f"Created: {contact.id}")

Salesforce (JWT Bearer):

import jwt
from datetime import datetime, timedelta

class SalesforceClient:
    def __init__(self, client_id: str, username: str, private_key: str):
        self.auth_url = "https://login.salesforce.com"
        self._authenticate(client_id, username, private_key)

    def _authenticate(self, client_id, username, private_key):
        payload = {
            "iss": client_id,
            "sub": username,
            "aud": self.auth_url,
            "exp": int((datetime.utcnow() + timedelta(minutes=3)).timestamp())
        }
        assertion = jwt.encode(payload, private_key, algorithm="RS256")

        response = httpx.post(f"{self.auth_url}/services/oauth2/token", data={
            "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
            "assertion": assertion
        })
        self.access_token = response.json()["access_token"]
        self.instance_url = response.json()["instance_url"]

</quick_start>

<success_criteria> A CRM integration is successful when:

  • API authentication works without errors
  • CRUD operations complete for all entity types
  • Rate limits are respected (Close: 100 req/10s, HubSpot: varies by tier)
  • Webhooks fire and process correctly
  • Data syncs bidirectionally without duplicates

</success_criteria>

<crm_comparison>

Platform Comparison

Feature Close HubSpot Salesforce
Auth API Key OAuth 2.0 / Private App JWT Bearer
Rate Limit 100 req/10s 100-200 req/10s by tier 100k req/day
Best For SMB sales, simplicity Tim's primary CRM (via Epiphan CRM MCP) Enterprise
Starting Price $49/user/mo Free (limited) $25/user/mo
API Access All plans Starter+ ($45+) All plans
Webhooks All plans Pro+ ($800+) All plans

Entity Mapping

Concept Close HubSpot Salesforce
Company lead company Account
Person contact contact Contact / Lead
Deal opportunity deal Opportunity
Activity activity engagement Task / Event
Custom Field custom.cf_xxx properties Field__c

Pipeline Stage Mapping

Stage Close HubSpot Salesforce
New Lead appointmentscheduled Prospecting
Qualified Contacted qualifiedtobuy Qualification
Demo Opportunity presentationscheduled Needs Analysis
Proposal Proposal decisionmakerboughtin Proposal/Price Quote
Won Won closedwon Closed Won
Lost Lost closedlost Closed Lost

</crm_comparison>

<close_patterns>

Close CRM (Daily Driver)

Note: Tim's primary CRM is HubSpot via Epiphan CRM MCP. Close CRM patterns are retained for reference but are not the active workflow.

See reference/close-crm-examples.md for query language examples, core operations (leads, opportunities, activities), and rate-limit headers.

See reference/close-deep-dive.md for query language, Smart Views, sequences, and reporting.

</close_patterns>

<hubspot_patterns>

HubSpot Integration

Python SDK Pattern

from hubspot import HubSpot
from hubspot.crm.deals import SimplePublicObjectInputForCreate
from hubspot.crm.contacts import PublicObjectSearchRequest

client = HubSpot(access_token=os.environ["HUBSPOT_ACCESS_TOKEN"])

# Create deal with association
deal = client.crm.deals.basic_api.create(
    SimplePublicObjectInputForCreate(properties={
        "dealname": "Enterprise Deal",
        "amount": "50000",
        "dealstage": "appointmentscheduled",
        "pipeline": "default"
    })
)

# Search contacts by email domain
search = PublicObjectSearchRequest(
    filter_groups=[{
        "filters": [{
            "propertyName": "email",
            "operator": "CONTAINS",
            "value": "@example.com"
        }]
    }],
    properties=["email", "firstname", "lastname"],
    limit=50
)
results = client.crm.contacts.search_api.do_search(search)

Association Types

From To Type ID
Contact Company 1
Contact Deal 4
Company Deal 6
Deal Contact 3

See reference/hubspot-patterns.md for batch operations, custom properties, and workflows.

</hubspot_patterns>

<salesforce_patterns>

Salesforce Integration

SOQL Query Patterns

-- Parent-child relationship (Contacts of Account)
SELECT Id, Name, (SELECT LastName, Email FROM Contacts)
FROM Account WHERE Industry = 'Technology'

-- Child-parent relationship
SELECT Id, FirstName, Account.Name, Account.Industry
FROM Contact WHERE Account.Industry = 'Technology'

-- Semi-join (Accounts with open Opportunities)
SELECT Id, Name FROM Account
WHERE Id IN (SELECT AccountId FROM Opportunity WHERE IsClosed = false)

REST API v59.0

def create_opportunity(self, data: dict) -> dict:
    """Required: Name, StageName, CloseDate."""
    response = self.client.post(
        f"{self.instance_url}/services/data/v59.0/sobjects/Opportunity/",
        headers={"Authorization": f"Bearer {self.access_token}"},
        json=data
    )
    return response.json()

# Composite API (batch up to 200 records)
def composite_create(self, records: list) -> dict:
    return self.client.post(
        f"{self.instance_url}/services/data/v59.0/composite/sobjects",
        json={"allOrNone": False, "records": records}
    )

See reference/salesforce-patterns.md for JWT setup, Platform Events, and bulk API.

</salesforce_patterns>

<webhook_patterns>

Webhook Handlers

See reference/webhook-handlers.md for the Close webhook FastAPI handler (with signature verification) and the full webhook event list.

</webhook_patterns>

<sync_architecture>

Cross-CRM Sync

Architecture

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   Close     │────▶│  Sync Layer  │◀────│  HubSpot    │
│  (Primary)  │◀────│  (Postgres)  │────▶│  (Marketing)│
└─────────────┘     └──────────────┘     └─────────────┘

Sync Record Schema

CREATE TABLE crm_sync_records (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    entity_type VARCHAR(50) NOT NULL,
    close_id VARCHAR(100) UNIQUE,
    hubspot_id VARCHAR(100) UNIQUE,
    salesforce_id VARCHAR(100) UNIQUE,
    email VARCHAR(255),
    company_name VARCHAR(255),
    last_synced_at TIMESTAMPTZ,
    sync_source VARCHAR(50),
    sync_hash VARCHAR(64)
);

CREATE INDEX idx_sync_email ON crm_sync_records(email);

Conflict Resolution

from enum import Enum

class ConflictStrategy(Enum):
    CLOSE_WINS = "close"      # Close is source of truth
    LAST_WRITE_WINS = "lww"   # Most recent update wins

def resolve_conflict(close_record, hubspot_record, strategy):
    if strategy == ConflictStrategy.CLOSE_WINS:
        merged = close_record.copy()
        for key, value in hubspot_record.items():
            if key not in merged or not merged[key]:
                merged[key] = value
        return merged

See reference/sync-patterns.md for deduplication, migration scripts, and bulk sync.

</sync_architecture>

<integration_points>

Integration Points (MCP Tools Available)

HubSpot / Epiphan CRM

Tool Purpose
hubspotsearchcompanies Find companies by name or domain
hubspotsearchcontacts Find contacts by email or name
hubspotsearchdeals Find deals by name or PO number
hubspotgetcompany Fetch company details by HubSpot ID
hubspotgetcontact Fetch contact details by HubSpot ID
hubspotgetdeal Fetch deal details by HubSpot ID
crmsearchcustomers Search customers (fuzzy-match company names)
crmgetcustomer Get customer details by CRM ID
crmsearchcustomers Search customers by company name or email
crmgetorder Get order details by order ID
crmgetcustomer_orders Get recent orders for a customer
analyticsgetdevice Get device details by serial number
analyticssearchby_email Find devices registered by email

Clay MCP Enrichment (mcp__claudeaiClay__)

Pattern: HubSpot → Apollo → Clay → HubSpot sync

Tool Purpose
find-and-enrich-company Find and enrich company by domain or LinkedIn URL
find-and-enrich-contacts-at-company Find contacts by role/title/location at a company
find-and-enrich-list-of-contacts Find specific named contacts at their companies
add-contact-data-points Queue contact enrichment (Email, Phone, Work History, Thought Leadership)
add-company-data-points Queue company enrichment (Tech Stack, Funding, Headcount, Competitors, etc.)
get-task Poll for enrichment results (check state: completed)
ask-question-about-accounts AI analysis of Salesforce account data
get-my-accounts Search Salesforce accounts by filters
get-task Retrieve task status and results by taskId

Cost Model:

  • Apollo: Free (but rate-limited)
  • Clay: Credits-based (~$150-300/month typical usage for BDR teams)
  • Waterfall strategy: Try Apollo first (fast, free), fallback to Clay for missing data (phones, emails, work history)

Call Data & Intelligence

Tool Purpose
ask_agent AI agent for complex CRM/analytics queries — activity history, engagement timelines, deal intelligence

</integration_points>

<file_locations>

Reference Files

CRM-Specific:

  • reference/close-deep-dive.md - Query language, Smart Views, sequences, reporting
  • reference/close-crm-examples.md - Close query language, core operations, rate-limit headers
  • reference/webhook-handlers.md - Close webhook FastAPI handler + event list
  • reference/hubspot-patterns.md - SDK patterns, batch operations, workflows
  • reference/salesforce-patterns.md - JWT auth, SOQL, Platform Events, bulk API

Operations:

  • reference/sync-patterns.md - Cross-CRM sync, deduplication, migration
  • reference/automation.md - Webhook setup, sequences, workflows

Templates:

  • templates/close-client.py - Full Close API client
  • templates/hubspot-client.py - HubSpot SDK wrapper
  • templates/sync-service.py - Cross-CRM sync service

</file_locations>

<routing>

Request Routing

User wants CRM integration: → Default to HubSpot (Epiphan CRM MCP) for Tim's BDR workflow → Provide auth setup + basic CRUD

User wants enrichment / contact data: → Use Clay MCP waterfall pattern (preferred for waterfall, credits OK) → Workflow: find-and-enrich-contacts-at-company → add-contact-data-points → poll get-task for results → Fallback: Apollo MCP for quick free enrichment (no polling needed) → Reference: See "Clay MCP Enrichment" in Integration Points above → Cost: Apollo free, Clay $150-300/mo estimate

User wants Close CRM: → Provide API key setup, query language → Reference: reference/close-deep-dive.md

User wants HubSpot: → Use Epiphan CRM MCP tools for direct integration → Available tools: hubspotsearchcompanies, hubspotsearchcontacts, hubspotsearchdeals, hubspotgetcompany, hubspotgetcontact, hubspotgetdeal → Company identification: crmsearchcustomers (fuzzy matching) → Activity data: ask_agent (CRM/analytics AI queries) → Enrichment: Clay MCP for waterfall enrichment before writeback to HubSpot → Reference: reference/hubspot-patterns.md

User wants Salesforce: → Provide JWT auth, SOQL patterns → Reference: reference/salesforce-patterns.md

User wants sync between CRMs: → Provide sync architecture, conflict resolution → Reference: reference/sync-patterns.md

User wants webhooks: → Provide handler pattern for specified CRM → Include signature verification

User wants phone verification / waterfall enrichment: → Use Clay MCP after Apollo: find-and-enrich-contacts-at-company → add-contact-data-points for Email/Phone → poll results → Clay aggregates 50+ providers for high match rates on phones and emails → See phone-verification-waterfall-skill for full implementation </routing>

<claymcppattern> See reference/clay-enrichment-patterns.md for Clay MCP waterfall enrichment workflow, tool prefix reference, cost considerations, env setup, and example session. </claymcppattern>

Emit Outcome Sidecar

Write to ~/.claude/skill-analytics/last-outcome-crm-integration.json: {"ts":"[UTC ISO8601]","skill":"crm-integration","version":"1.0.0","variant":"default","status":"[success|partial|error]","runtimems":[ms],"metrics":{"integrationsconfigured":[n],"recordssynced":[n]},"error":null,"sessionid":"[YYYY-MM-DD]"}