This wraps HubSpot's v4 flows API through the agent CLI (the `hubspot` command, not the `hs` developer CLI). You get list, get, create, update, and delete for workflows. The update is a full PUT, so you fetch the current JSON, edit it, then push it back with the revisionId intact. No search command exists, so finding by name means piping list output through jq. The create dry run doesn't validate schema, only that your JSON parses, which is annoying. Branching and convergence work by pointing nextActionId references at shared actions. Safest path is to get an existing workflow as a template rather than hand writing the body from scratch.
npx -y skills add hubspot/agent-cli-skills --skill workflow-automation --agent claude-codeInstalls into .claude/skills of the current project.
Two different HubSpot CLIs share a confusing resemblance — don't mix them up:
hubspot — the HubSpot agent CLI that this skill library targets. It manages CRM data and automation, and it does have native workflow commands: hubspot workflows list|get|create|update|delete.hs — the HubSpot developer CLI (@hubspot/cli), for building dev projects: themes, modules, serverless functions, UI extensions, and private apps (hs project, hs upload, hs create). It does not create or manage workflow records.To create or manage a workflow, use hubspot workflows ... — not hs.
If anything here ever drifts, hubspot workflows --help and hs --help are authoritative.
| File | When to use |
|---|---|
resources/workflow-json-reference.md | Body shape for create/update — the action graph, branching/convergence, enrollment, full-PUT pitfall |
resources/example-contact-flow.json | Minimal valid CONTACT_FLOW skeleton for hubspot workflows create --file |
resources/example-branching-flow.json | Illustrates branch convergence — two paths pointing connection.nextActionId at one shared downstream action |
hubspot workflows --help lists five subcommands: list, get, create, update, delete. There is no search — finding by name is list | jq. For JSONL piping, pagination, and destructive dry-run/digest/confirm patterns, this skill builds on bulk-operations/SKILL.md — re-read that first.
hubspot workflows list # JSONL: id, name, isEnabled, type, objectTypeId, revisionId
hubspot workflows list --format table # for human scanning
# Find by name — case-insensitive substring
hubspot workflows list | jq -c 'select(.name | test("Welcome"; "i"))'
# Exact match
hubspot workflows list | jq -c 'select(.name == "MQL Nurture")'
List is paginated at 100 per call. Loop with --after until meta.next is empty — see bulk-operations/SKILL.md "Pagination". See resources/json-patterns.md in bulk-operations for more jq filters.
hubspot workflows get 12345678 # one
hubspot workflows get 12345678 87654321 # batch positional
printf '%s\n' 12345678 87654321 | hubspot workflows get # batch stdin
hubspot workflows get 12345678 > workflow.json # save for editing
Get returns the full body (actions, enrollmentCriteria, revisionId, …) — the shape required by create/update. See resources/workflow-json-reference.md.
hubspot workflows create --file workflow.json --dry-run
hubspot workflows create --file workflow.json
cat workflow.json | hubspot workflows create # stdin also works
Set type (CONTACT_FLOW or PLATFORM_FLOW), flowType (WORKFLOW), and objectTypeId (e.g. 0-1 for contacts) — all required on create. See resources/workflow-json-reference.md for the body shape and resources/example-contact-flow.json for the minimal template. Easiest path: get an existing similar workflow as a starting template rather than hand-writing the JSON.
Pitfall: create --dry-run does not validate the body. It echoes the JSON back with ok:true and makes no API call — a green dry-run proves only that the input is well-formed JSON, not that it's a valid create (a body missing type/flowType/objectTypeId/actions still returns ok:true). The only real validation is the live create. By contrast, update --dry-run does reject a body missing required fields like revisionId.
Branching and convergence. A LIST_BRANCH action forks the path on filter criteria; each branch — and the defaultBranch — carries a connection to the action it continues to. Because connections target actions by nextActionId, branches can converge: point two branches at the same actionId and both paths continue to one shared action, no duplication. See the branching section of resources/workflow-json-reference.md and resources/example-branching-flow.json.
Update is a full replace. The body must include revisionId (from get) and type. Read-only fields (createdAt, updatedAt, dataSources) are stripped automatically. Update is gated: dry-run first, then re-run with --digest <hash> --confirm <flowId>.
# 1. Fetch current state
hubspot workflows get 12345678 > workflow.json
# 2. Edit workflow.json (preserve revisionId, type, and any field you want to keep)
# 3. Dry-run — emits a digest
hubspot workflows update 12345678 --file workflow.json --dry-run
# 4. Apply — confirm value is the flow id
hubspot workflows update 12345678 --file workflow.json \
--digest blast-xxxxxxxx --confirm 12345678
Pitfall: partial bodies silently clear fields. Sending only actions will wipe enrollmentCriteria. Always start from the full get response.
# 1. Dry-run — emits a digest + the confirm hint
hubspot workflows delete 12345678 --dry-run
# 2. Re-run with digest + confirm. Confirm value is the workflow's NAME, not its id.
hubspot workflows delete 12345678 --digest blast-xxxxxxxx --confirm "New lead routing"
The dry-run output includes an apply_command_hint — copy the exact confirm string from there to avoid quoting surprises. Workflows cannot be restored through the automation API after deletion; check hubspot history --since 1h for an audit record. The full safety pattern (digest, 5-minute expiry, history recovery) is documented in bulk-operations/SKILL.md "Safe destructive workflow".
hubspot workflows search — list | jq is the workaround.dataSources is read-only — cannot be rewired via update.sickn33/antigravity-awesome-skills
moizibnyousaf/ai-agent-skills
github/awesome-copilot