---
name: hubspot-weekly-pipeline-report
description: "Every Monday: open pipeline by stage, the deals that changed stage last week, and what was created, won and lost. Use when the user asks for this, or when it runs on a schedule."
---

# HubSpot weekly pipeline report

Every Monday: open pipeline by stage, the deals that changed stage last week, and what was created, won and lost.

The Monday pipeline review usually opens with someone sharing the HubSpot deals board and scrolling column by column. This skill does that pass before the meeting: it totals open deals by stage, reads the stage history of every deal touched in the last seven days to see what actually advanced or slid back, and lists what was created, won and lost.

Sales leads and founders get one number to watch, open pipeline, and a short list of the deals that changed it. Deals that sat still stay out of the way.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- A HubSpot private app token in `HUBSPOT_ACCESS_TOKEN` with `crm.objects.deals.read` and `crm.objects.owners.read`, or a HubSpot connector with the same read access.
- Which deal pipeline to report on, if the account has more than one.

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **Map the pipeline stages** (HubSpot): Call `GET /crm/v3/pipelines/deals` and keep each stage's `id`, `label`, `displayOrder` and `metadata.isClosed`, so stage IDs such as `appointmentscheduled` or `98712345` read as names. Use the pipeline the team reviews (often `default`).
2. **Total the open pipeline** (HubSpot): Page through `POST /crm/v3/objects/deals/search` with `pipeline EQ <id>` and `dealstage NOT_IN` the closed stage IDs, requesting `dealname`, `amount`, `dealstage`, `hubspot_owner_id` and `createdate` with `limit: 200` (the search maximum) and the `after` cursor. Sum `amount` per stage and count deals with no amount on a line of their own.
3. **Find what changed stage** (HubSpot): Search for deals with `hs_lastmodifieddate GTE` seven days ago (epoch milliseconds), then call `POST /crm/v3/objects/deals/batch/read` with `propertiesWithHistory: ["dealstage"]`. A deal moved if its stage history has an entry with a `timestamp` inside the window; compare the `displayOrder` of the old and new stage to call it forward or back.
4. **Collect new, won and lost**: New deals have a `createdate` inside the window. Won and lost deals are those whose stage history entered the closed won or closed lost stage this week; keep `closed_lost_reason` for the lost ones. Map `hubspot_owner_id` to names with `GET /crm/v3/owners`.
5. **Write the report**: Save this week's totals by stage to a small JSON file and compare with last Monday's. Then write open pipeline and its change, the table by stage, up to 8 stage moves with owner and amount, and new, won and lost, leading with the single biggest change.

## Route B: the browser

### What you need

- Signed in to HubSpot as a user who can view all deals in the pipeline, not only their own.
- Know which deal pipeline to report on if the account has more than one.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://app.hubspot.com/contacts/. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **Open the deals board**: HubSpot opens your default account on the Contacts page; switch accounts in the top right if you have several. Go to **CRM > Deals** and pick the pipeline the team reviews from the pipeline dropdown above the board.
2. **Read the open stages**: In the board view, every stage column shows its deal count and total amount in the header. Write them down for each open stage, and count the cards whose amount is blank on a separate line. Last Monday's numbers come from your previous report.
3. **Find the deals that moved**: Switch to the list view (the table icon), add the filter **Last modified date** is **Last 7 days** and sort by it. Open each deal, hover **Deal stage** in the About section and open its property history (the clock icon): a stage set inside the last 7 days is a move, forward or back by the pipeline order.
4. **Collect new, won and lost**: Change the filter to **Create date** is **Last 7 days** for new deals. Then filter **Deal stage** is **Closed won** with **Close date** is **Last 7 days**, and the same for **Closed lost**, adding the **Closed lost reason** column with **Edit columns**.
5. **Write the report**: Open pipeline and its change since last Monday, the table by stage, up to 8 stage moves with owner and amount, and new, won and lost, leading with the biggest change.

Note: Reading the column headers is quick. Opening deals one by one for stage history gets slow past 30 or so modified deals; with more, build a custom Deals report under Reports that uses the Deal stage property history with a 7-day date filter, which lists every stage change in one table. The board totals and the API sum match as long as the same pipeline is selected.

## The report

- **Open pipeline** today and the change since last Monday.
- **By stage**: deal count and amount in each open stage, with each stage's change.
- **Stage moves**: deals that advanced or slid back this week, with owner and amount.
- **New, won and lost**: counts and amounts, with the closed lost reason where one was recorded.
- One line on the deal to raise first in the pipeline review.

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "hubspot-weekly-pipeline-report/<date of this run, e.g. 2026-10-16>",
  "item_key": "hubspot-weekly-pipeline-report",
  "project": "Acme",
  "source": "HubSpot weekly pipeline report skill",
  "kind": "metric",
  "title": "Open pipeline up $86k this week",
  "metric": {
    "label": "Open pipeline",
    "value": 1284000,
    "prefix": "$",
    "better": "higher",
    "period_start": "<start of the period, ISO 8601>",
    "period_end": "<end of the period, ISO 8601>"
  },
  "glance": [
    {
      "type": "Grid",
      "props": {
        "columns": 3
      },
      "children": [
        {
          "type": "Stat",
          "props": {
            "label": "New deals",
            "value": 14,
            "delta": 27
          }
        },
        {
          "type": "Stat",
          "props": {
            "label": "Closed won",
            "value": "$118k",
            "tone": "ok"
          }
        },
        {
          "type": "Stat",
          "props": {
            "label": "Closed lost",
            "value": "$64k"
          }
        }
      ]
    },
    {
      "type": "Badges",
      "props": {
        "items": [
          {
            "label": "6 moved forward",
            "tone": "ok"
          },
          {
            "label": "2 slid back",
            "tone": "warn"
          },
          {
            "label": "3 open deals with no amount"
          }
        ]
      }
    }
  ],
  "widget": [
    {
      "type": "Table",
      "props": {
        "columns": [
          "Stage",
          "Deals",
          "Amount",
          "vs last week"
        ],
        "align": [
          "left",
          "right",
          "right",
          "right"
        ],
        "rows": [
          [
            "Appointment scheduled",
            18,
            "$212,000",
            "+$24,000"
          ],
          [
            "Qualified to buy",
            15,
            "$286,000",
            "+$41,000"
          ],
          [
            "Presentation scheduled",
            11,
            "$248,000",
            "-$18,000"
          ],
          [
            "Decision maker bought-in",
            9,
            "$301,000",
            "+$52,000"
          ],
          [
            "Contract sent",
            5,
            "$237,000",
            "-$13,000"
          ]
        ]
      }
    },
    {
      "type": "Table",
      "props": {
        "columns": [
          "Deal",
          "Owner",
          "Stage move",
          "Amount"
        ],
        "align": [
          "left",
          "left",
          "left",
          "right"
        ],
        "rows": [
          [
            "Northwind renewal",
            "Dana",
            "Presentation → Decision maker",
            "$64,000"
          ],
          [
            "Contoso data platform",
            "Sam",
            "Qualified → Presentation",
            "$38,000"
          ],
          [
            "Fabrikam pilot",
            "Priya",
            "Decision maker → Contract sent",
            "$27,000"
          ],
          [
            "Tailspin annual plan",
            "Lena",
            "Appointment → Qualified",
            "$22,000"
          ],
          [
            "Wingtip seats",
            "Theo",
            "Qualified → Presentation",
            "$18,000"
          ],
          [
            "Adatum add-on",
            "Sam",
            "Appointment → Qualified",
            "$12,000"
          ],
          [
            "Proseware expansion",
            "Marco",
            "Contract sent → Presentation (back)",
            "$45,000"
          ],
          [
            "Litware renewal",
            "Dana",
            "Decision maker → Qualified (back)",
            "$31,000"
          ]
        ]
      }
    },
    {
      "type": "Callout",
      "props": {
        "text": "Raise first: Proseware ($45,000) went back from Contract sent to Presentation scheduled.",
        "tone": "warn"
      }
    }
  ],
  "size": "md"
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

Set `period_start` and `period_end` to the window the number covers: the tile names it from them ("Last 7 days", "Today", "This month"). For a count right now (open items, a balance), send `"period_label": ""` so no period shows; for another name, send it as `period_label` (at most 24 characters).

## Run it on a schedule

Suggested: Mondays at 8:00 (`0 8 * * 1`). From cron, with the agent signed in on that machine:

```bash
0 8 * * 1 claude -p "Run the hubspot-weekly-pipeline-report skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/hubspot-weekly-pipeline-report#schedule

Source: https://briefkin.dev/skills/hubspot-weekly-pipeline-report
