PluginBench
Skill
Review
Audit score 70

crm-lookup

hubspot/agent-cli-skills

Find CRM records by ID, email, domain, or name, and traverse associations for complete account context.

What is crm-lookup?

Lookup contacts, companies, deals, and tickets in HubSpot by various criteria (ID, email, domain, name fragment). Traverse associations to see related records—e.g., all contacts at a company or all deals for a contact. Read-only; pairs with bulk-operations skill for writes.

  • Batch-lookup records by ID (up to ~100 per call)
  • Exact-match search by email or domain (case-insensitive)
  • Token-based partial name search with client-side substring filtering
  • List all associated records between object types (contacts↔companies, contacts↔deals, etc.)
  • Retrieve a record plus its full association graph in ordered CLI calls

How to install crm-lookup

npx skills add https://github.com/hubspot/agent-cli-skills --skill crm-lookup
Prerequisites
  • HubSpot CLI installed and authenticated (`hubspot auth`)
  • Knowledge of object types (contacts, companies, deals, tickets) and their properties
  • Familiarity with `jq` for client-side filtering (optional but recommended)
Claude Code
Cursor
Windsurf
Cline

How to use crm-lookup

  1. 1.Run `hubspot properties list --type <type>` to see available fields for your object
  2. 2.Use `hubspot objects search --type <type> --filter <criterion>` for email/domain/name lookups
  3. 3.Pipe search results to `jq -c '{id}'` to extract IDs for batch operations
  4. 4.Use `hubspot associations list --from <type>:<id> --to <type>` to find related records
  5. 5.Chain association results into `hubspot objects get` to fetch full details of related records

Use cases

Good for
  • Find all contacts at a company by domain lookup, then batch-fetch their details
  • Look up a deal by name fragment, then list all associated contacts and their lifecycle stages
  • Retrieve a contact by email, fetch their company record, and list all open deals for that company
  • Batch-get contact records by ID and filter by campaign attribution properties
  • Traverse from a company to all contacts to all their associated deals for pipeline analysis
Who it's for
  • Sales development reps researching accounts and contacts
  • Revenue operations analysts building reports or data pipelines
  • Customer success managers finding account associations
  • Developers building CRM automation workflows

crm-lookup FAQ

Can I search by substring or partial text?

Token-based search (`~`) matches whole space-separated words. For substring matching, use `jq` client-side filtering after the search: `| jq -c 'select(.properties.fieldname | contains("substring"))'`.

How do I find all contacts at a company?

Look up the company by domain, extract its ID, then run `hubspot associations list --from companies:<id> --to contacts | jq -c '{id}' | hubspot objects get --type contacts --properties email,firstname,lastname`.

What's the difference between this skill and bulk-operations?

crm-lookup is read-only for finding and traversing records. bulk-operations handles writes (update, delete, merge) with safety flows like `--dry-run` and `--confirm`.

Can I use xargs to loop over association results?

No—avoid `xargs -I{} hubspot objects get …` because it spawns one process per record. Instead, pipe to `hubspot objects get` once with all IDs for batch efficiency.

How do I filter for open deals only?

Search all deals associated with a contact, then pipe to `jq -c 'select(.properties.hs_is_closed != "true")'` to filter client-side.

Full instructions (SKILL.md)

Source of truth, from hubspot/agent-cli-skills.


name: crm-lookup description: Find a specific CRM record by ID, email, domain, or name fragment, and traverse associations for the full account picture. triggers:

  • "find contact"
  • "find contact by email"
  • "find company by domain"
  • "look up deal"
  • "contacts at this company"
  • "deals for this contact"
  • "find record"

Source of truth

hubspot <command> --help is authoritative. Read bulk-operations/SKILL.md first — it owns JSONL piping, pagination, batch-get-via-stdin, and the safety flow for any write that comes after a lookup. This skill is read-only.

Pick properties from the live schema

Schemas drift. Run hubspot properties list --type <type> for the live set. First-pass --properties for a brief:

Object--properties
contactsemail,firstname,lastname,company,phone,lifecyclestage,hubspot_owner_id
companiesname,domain,industry,annualrevenue,numberofemployees,hubspot_owner_id
dealsdealname,amount,dealstage,closedate,hubspot_owner_id,hs_is_closed_won
ticketssubject,hs_pipeline_stage,hs_ticket_priority,hubspot_owner_id

Contact ad/campaign attribution lives on hs_analytics_* (e.g. hs_analytics_source, hs_analytics_source_data_1/_2, hs_analytics_first_touch_converting_campaign, hs_analytics_last_touch_converting_campaign). Full list: hubspot properties list --type contacts | grep hs_analytics_.

1. Lookup by ID

Up to ~100 IDs in a single batch call:

hubspot objects get --type contacts 12345 67890 23456 --properties email,firstname,lastname,company,phone,lifecyclestage

2. Find one by email / domain (exact match)

email/domain are exact-match — normalize to lowercase. Multiple --filter flags are OR'd.

hubspot objects search --type contacts --filter "email=jane@acme.com" \
  --properties email,firstname,lastname,company,lifecyclestage,hubspot_owner_id

hubspot objects search --type companies --filter "domain=acme.com" \
  --properties name,domain,industry,annualrevenue,hubspot_owner_id

# OR — multiple emails in one call
hubspot objects search --type contacts \
  --filter "email=alice@acme.com" --filter "email=bob@acme.com" --properties email,firstname

3. Find by partial name (token + client-side narrowing)

~ is CONTAINS_TOKEN — matches whole space-separated words. dealname~acme finds "Acme Renewal" but not "AcmeCorp". For substring, pipe to jq. There's no full-text search across all fields — pick the property.

hubspot objects search --type deals --filter "dealname~acme" --properties dealname,amount,dealstage \
| jq -c 'select(.properties.dealname | ascii_downcase | contains("acme corp"))'

4. Find all associated records (two CLI calls, not xargs)

Pattern: associations list → jq -c '{id}' → objects get batch. Never xargs -I{} hubspot objects get … — that spawns one process per record. Use plural in --from (contacts:, companies:, deals:); --help shows singular but only plural avoids a warning.

# All contacts at a company
hubspot associations list --from companies:67890 --to contacts \
| jq -c '{id}' \
| hubspot objects get --type contacts --properties email,firstname,lastname,jobtitle

# Open deals for a contact (filter client-side; "open" varies by pipeline)
hubspot associations list --from contacts:12345 --to deals | jq -c '{id}' \
| hubspot objects get --type deals --properties dealname,amount,dealstage,hs_is_closed \
| jq -c 'select(.properties.hs_is_closed != "true")'

5. Get a record plus its associations

contact_id=12345
hubspot objects get --type contacts $contact_id --properties email,firstname,lastname,company,lifecyclestage

# Associated company (usually one)
hubspot associations list --from contacts:$contact_id --to companies | jq -c '{id}' | head -1 \
| hubspot objects get --type companies --properties name,domain,industry,annualrevenue

# Associated deals
hubspot associations list --from contacts:$contact_id --to deals | jq -c '{id}' \
| hubspot objects get --type deals --properties dealname,amount,dealstage,closedate

Constraints

  • Search returns ≤100 per page. For more, use the pagination loop in bulk-operations/SKILL.md.
  • ~ is token-based; substring filtering happens in jq after the search.
  • If the lookup feeds a write (update, delete, merge), follow the --dry-run → digest → --confirm flow in bulk-operations/SKILL.md.