team-ownership
hubspot/agent-cli-skills
Assign, reassign, and audit CRM record ownership across contacts, companies, deals, and tickets.
What is team-ownership?
Manage record ownership in HubSpot CRM by resolving owner IDs, finding records by owner, and bulk-reassigning across object types. Use this when reps transition, accounts need redistribution, or you need ownership audits. Built on the bulk-operations skill.
- Resolve email addresses to owner IDs and cache them for safe reassignment
- Search for records owned by a specific user across all four object types (contacts, companies, deals, tickets)
- Bulk reassign ownership with dry-run validation and safe destructive workflow (digest/confirm for >100 records)
- Handle rep-leaves workflows by looping over all object types and transferring records to a new owner
- Find unowned records using negation filters (e.g., !hubspot_owner_id)
- Generate team-level ownership views by grouping records and joining to human-readable owner emails
How to install team-ownership
npx skills add https://github.com/hubspot/agent-cli-skills --skill team-ownership- Install the bulk-operations skill first (this skill is built on it)
- Access to hubspot CLI with owner and object search/update commands
- Portal-specific owner IDs (resolved via `hubspot owners list`, not hardcoded)
How to use team-ownership
- 1.Resolve email addresses to owner IDs using `hubspot owners list` and jq filtering
- 2.Search for records owned by a user with `hubspot objects search --filter "hubspot_owner_id=$ID"`
- 3.Reshape search results into update format using jq: `{id, properties:{hubspot_owner_id:$new_id}}`
- 4.Pipe reshaped results to `hubspot objects update` with `--dry-run` first
- 5.Review the digest output; re-run with `--digest` and `--confirm` flags for >100 records
- 6.For rep-leaves workflows, loop over all four object types (contacts, companies, deals, tickets) and repeat steps 2–5
- 7.Generate team-level views by grouping records by owner_id and joining to `hubspot owners list` for email display
Use cases
- A sales rep is leaving: transfer all their contacts, companies, deals, and tickets to a replacement rep
- Redistribute a book of business: reassign 500+ deals from one owner to multiple new owners with audit trail
- Audit who owns what: generate a report of open deals by owner to identify coverage gaps
- Find orphaned records: identify contacts, companies, or deals with no owner assigned
- Single-record assignment: quickly assign a specific contact or deal to a new owner
- Sales operations managers handling rep transitions or territory changes
- CRM administrators auditing and rebalancing record ownership
- Sales leaders generating ownership reports for team planning
- Anyone managing bulk record reassignments in HubSpot
team-ownership FAQ
Owner IDs are portal-specific and change between environments. Always resolve from email using `hubspot owners list | jq` to ensure portability and correctness.
The dry-run emits a digest hash and record count. Re-run the command without `--dry-run` but add `--digest <hash> --confirm <count>` to proceed safely.
Use the negation filter: `hubspot objects search --type deals --filter "!hubspot_owner_id"` to find unowned records.
Yes: `hubspot objects update --type contacts 12345 --property hubspot_owner_id=$TO_ID` updates one record directly.
Use `hubspot history --since 1h` to list affected record IDs, then reassign them back to the correct owner.
Full instructions (SKILL.md)
Source of truth, from hubspot/agent-cli-skills.
name: team-ownership
description: Assign and reassign CRM record ownership, audit who-owns-what across object types, and handle rep transitions. Built on bulk-operations.
triggers:
- "assign owner"
- "reassign records"
- "ownership audit"
- "rep leaving"
- "transfer records"
- "change owner"
- "find records owned by"
- "redistribute accounts"
Prereq: read bulk-operations/SKILL.md first. JSONL piping, pagination, dry-run/digest/confirm, and hubspot history recovery live there. Reshape patterns live in bulk-operations/resources/json-patterns.md.
hubspot_owner_id is a string field on contacts, companies, deals, and tickets. Owners are CRM users — hubspot owners list returns them; there is no teams object, so team-level views are client-side groupings by hubspot_owner_id.
1. Resolve email → owner ID
Never hardcode IDs — they are portal-specific. Resolve, then cache:
FROM_ID=$(hubspot owners list | jq -r 'select(.email=="sarah@company.com") | .id')
TO_ID=$(hubspot owners list | jq -r 'select(.email=="mike@company.com") | .id')
2. Find records for an owner
Same filter across all four object types. Add object-specific --properties for context. Unowned records use the !property form.
hubspot objects search --type contacts --filter "hubspot_owner_id=$FROM_ID" --properties email,firstname,lifecyclestage
hubspot objects search --type companies --filter "hubspot_owner_id=$FROM_ID" --properties name,domain
hubspot objects search --type deals --filter "hubspot_owner_id=$FROM_ID" --properties dealname,dealstage,amount
hubspot objects search --type tickets --filter "hubspot_owner_id=$FROM_ID" --properties subject,hs_pipeline_stage
# Records with no owner at all
hubspot objects search --type deals --filter "!hubspot_owner_id" --properties dealname,amount
100 hits — page with the
--afterloop frombulk-operations. Counting only: pipe towc -l.
3. Bulk reassign — search → update
Reshape each search row into {id, properties:{hubspot_owner_id}} and pipe to objects update. Always dry-run first; for >100 rows the dry-run emits a digest + apply_command_hint — re-run with --digest/--confirm (see bulk-operations/SKILL.md § "Safe destructive workflow").
# Dry-run
hubspot objects search --type contacts --filter "hubspot_owner_id=$FROM_ID" \
| jq -c --arg to "$TO_ID" '{id, properties:{hubspot_owner_id:$to}}' \
| hubspot objects update --type contacts --dry-run
# Execute — ≤100: drop --dry-run. >100: append --digest <hash> --confirm <count>.
hubspot objects search --type contacts --filter "hubspot_owner_id=$FROM_ID" \
| jq -c --arg to "$TO_ID" '{id, properties:{hubspot_owner_id:$to}}' \
| hubspot objects update --type contacts
Single-record assignment — no stdin, no jq:
hubspot objects update --type contacts 12345 --property hubspot_owner_id=$TO_ID
4. Rep-leaves workflow
Loop over the four object types the rep touches:
FROM_ID=$(hubspot owners list | jq -r 'select(.email=="leaving@company.com") | .id')
TO_ID=$(hubspot owners list | jq -r 'select(.email=="taking-over@company.com") | .id')
for type in contacts companies deals tickets; do
echo "── $type ──"
hubspot objects search --type "$type" --filter "hubspot_owner_id=$FROM_ID" \
| jq -c --arg to "$TO_ID" '{id, properties:{hubspot_owner_id:$to}}' \
| hubspot objects update --type "$type" --dry-run
done
Review each digest line, then re-run without --dry-run (adding --digest/--confirm per type when escalated). Mis-reassigned? hubspot history --since 1h lists the affected IDs.
5. Team-level views (client-side grouping)
Group records by hubspot_owner_id, join to owners list for human-readable emails:
hubspot objects search --type deals --filter "dealstage!=closedwon AND dealstage!=closedlost" \
--properties hubspot_owner_id --format json \
| jq '.data | group_by(.properties.hubspot_owner_id)
| map({owner_id: .[0].properties.hubspot_owner_id, count: length})' \
> /tmp/by-owner.json
hubspot owners list \
| jq --slurpfile by /tmp/by-owner.json -r \
'. as $o | $by[0][] | select(.owner_id==$o.id) | "\($o.email)\t\(.count)"'
Related skills
More from hubspot/agent-cli-skills and the wider catalog.

ticket-resolution
Create, triage, advance, and close HubSpot support tickets with pipeline discovery and bulk operations.

workflow-automation
Manage HubSpot v4 workflows (list, create, update, delete) via the hubspot agent CLI.

audience-targeting
Build targeted contact segments by filtering on lifecycle, engagement, job title, geography, and firmographics—then export as JSONL.

bulk-operations
Foundation patterns for bulk operations in the HubSpot CLI — JSONL piping, pagination, dry-run, and recovery.

hf-cli
Hugging Face Hub CLI for managing models, datasets, spaces, buckets, and infrastructure.

huggingface-best
Find the best AI model for your task by querying HuggingFace benchmark leaderboards and filtering by device constraints.