Request discount approval in Slack for HubSpot deals using a Claude Code skill
Install this skill
Download the skill archive and extract it into your .claude/skills/ directory.
discount-audit.skill.zipPrerequisites
This skill works with any agent that supports the Claude Code skills standard, including Claude Code, Claude Cowork, OpenAI Codex, and Google Antigravity.
- One of the agents listed above
- HubSpot private app with
crm.objects.deals.readscope - Slack bot with
chat:writepermission, added to the target channel - Custom HubSpot deal properties:
discount_percent(number) anddiscount_approval(dropdown with Approved / Pending / Denied)
Why a Claude Code skill?
The other approaches in this guide are deterministic: they run the same logic every time, the same way. An Claude Code skill is different. You tell Claude what you want in plain language, and the skill gives it enough context to do it reliably.
That means you can say:
- "Audit deals with discounts over 15% and flag unapproved ones to Slack"
- "Which deals have discounts above 20% this week?"
- "Post a summary of unapproved discounts to #deal-desk instead"
The skill contains workflow guidelines, API reference materials, and a message template that the agent reads on demand. When you invoke the skill, Claude reads these files, writes a script on the fly, runs it, and reports results. If you ask for something different next time — a higher threshold, a different channel, a summary grouped by rep — the agent adapts without you touching any code.
How it works
The skill directory has three parts:
SKILL.md— workflow guidelines telling the agent what steps to follow, which env vars to use, and what pitfalls to avoidreferences/— HubSpot API patterns (endpoints, request shapes, response formats) so the agent calls the right APIs with the right parameterstemplates/— a Slack Block Kit template so messages are consistently formatted across runs
When invoked, the agent reads SKILL.md, consults the reference and template files as needed, writes a Python script, executes it, and reports what it posted. The reference files act as guardrails — the agent knows exactly which endpoints to hit and what the responses look like, so it doesn't have to guess.
What is a Claude Code skill?
An Claude Code skill is a reusable command you add to your project that Claude Code can run on demand. Skills live in a .claude/skills/ directory and are defined by a SKILL.md file that tells the agent what the skill does, when to run it, and what tools it's allowed to use.
In this skill, the agent doesn't run a pre-written script. Instead, SKILL.md provides workflow guidelines and points to reference files — API documentation, message templates — that the agent reads to generate and execute code itself. This is the key difference from a traditional script: the agent can adapt its approach based on what you ask for while still using the right APIs and message formats.
Once installed, you can invoke a skill as a slash command (e.g., /discount-audit), or the agent will use it automatically when you give it a task where the skill is relevant. Skills are portable — anyone who clones your repo gets the same commands.
Step 1: Create the skill directory
mkdir -p .claude/skills/discount-audit/{templates,references}This creates the layout:
.claude/skills/discount-audit/
├── SKILL.md # workflow guidelines + config
├── templates/
│ └── slack-alert.md # Block Kit template for Slack messages
└── references/
└── hubspot-deals-api.md # HubSpot API patternsStep 2: Write the SKILL.md
Create .claude/skills/discount-audit/SKILL.md:
---
name: discount-audit
description: Find HubSpot deals with unapproved discounts above threshold and post a summary to Slack
disable-model-invocation: true
allowed-tools: Bash, Read
---
## Goal
Search HubSpot for deals where `discount_percent` exceeds a threshold (default: 15%) and `discount_approval` is not "Approved". Post a consolidated summary to Slack listing each deal that needs manager review.
## Configuration
Read these environment variables:
- `HUBSPOT_ACCESS_TOKEN` — HubSpot private app token (required)
- `SLACK_BOT_TOKEN` — Slack bot token starting with xoxb- (required)
- `SLACK_CHANNEL_ID` — Slack channel ID starting with C (required)
Default discount threshold: 15%. The user may request a different threshold.
## Workflow
1. Validate that all required env vars are set. If any are missing, print which ones and exit.
2. Search for deals with `discount_percent` greater than the threshold using the HubSpot CRM Search API. See `references/hubspot-deals-api.md` for the request and response format.
3. Filter out deals where `discount_approval` is already "Approved" — this must be done client-side since HubSpot's search API has limited NOT_EQUAL support on custom properties.
4. If no unapproved deals remain, print "No unapproved high-discount deals found" and exit.
5. Build a single Slack message listing all unapproved deals using the template in `templates/slack-alert.md`.
6. Post the message to Slack and print a summary of how many deals were flagged.
## Important notes
- HubSpot's search API uses internal property names, not display labels. The custom properties must be named exactly `discount_percent` and `discount_approval`.
- The search API `GT` filter on `discount_percent` requires the value as a string (e.g., `"15"` not `15`).
- `SLACK_CHANNEL_ID` must be the channel ID (starts with `C`), not the channel name. The `chat.postMessage` API requires the ID.
- The Slack bot must be invited to the target channel or `chat.postMessage` will fail with `not_in_channel`.
- Use `urllib.request` for HTTP calls (no external dependencies required).Understanding the SKILL.md
Unlike the script-based approach, this SKILL.md doesn't contain a Run: command pointing to a script. Instead, it provides:
| Section | Purpose |
|---|---|
| Goal | Tells the agent what outcome to produce |
| Configuration | Which env vars to read and what defaults to use |
| Workflow | Numbered steps with pointers to reference files |
| Important notes | Non-obvious context that prevents common mistakes |
The allowed-tools: Bash, Read setting lets the agent both read reference files and execute code. The agent writes its own script based on the workflow steps and reference materials.
Step 3: Add reference files
templates/slack-alert.md
Create .claude/skills/discount-audit/templates/slack-alert.md:
# Slack Alert Template
Use this Block Kit structure for the discount audit summary message.
## Block Kit JSON
```json
{
"channel": "<SLACK_CHANNEL_ID>",
"text": "<count> deal(s) need discount approval",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Discount Approval Needed"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*<count> deal(s)* have discounts above <threshold>% without approval:\n\n- <https://app.hubspot.com/contacts/<PORTAL_ID>/deal/<DEAL_ID>|Deal Name> — $amount at discount%\n- ..."
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Review each deal and update the discount_approval property in HubSpot."
}
]
}
]
}
```
## Notes
- The top-level `text` field is required by the Slack API as a fallback for notifications and accessibility. Always include it.
- The HubSpot deal link format: `https://app.hubspot.com/contacts/<PORTAL_ID>/deal/<DEAL_ID>` (if portal ID is known) or `https://app.hubspot.com/contacts/deal/<DEAL_ID>`.
- List all unapproved deals in a single message rather than posting one message per deal.
- Include the deal name, amount, and discount percentage for each deal.references/hubspot-deals-api.md
Create .claude/skills/discount-audit/references/hubspot-deals-api.md:
# HubSpot Deals API Reference
## Search for deals by custom property
Use the CRM Search API to find deals where a custom property exceeds a value.
**Request:**
```
POST https://api.hubapi.com/crm/v3/objects/deals/search
Authorization: Bearer <HUBSPOT_ACCESS_TOKEN>
Content-Type: application/json
```
**Body:**
```json
{
"filterGroups": [
{
"filters": [
{
"propertyName": "discount_percent",
"operator": "GT",
"value": "<threshold>"
}
]
}
],
"properties": [
"dealname", "amount", "discount_percent",
"discount_approval", "hubspot_owner_id", "dealstage"
],
"limit": 100
}
```
- The `value` must be a string, even for number properties (e.g., `"15"` not `15`).
- `limit` max is 100. If there are more results, use the `after` cursor from `paging.next.after` in the response to paginate.
**Response shape:**
```json
{
"total": 5,
"results": [
{
"id": "12345",
"properties": {
"dealname": "Acme Corp Annual Contract",
"amount": "72000",
"discount_percent": "22",
"discount_approval": "",
"hubspot_owner_id": "67890",
"dealstage": "contractsent"
}
}
],
"paging": {
"next": {
"after": "100"
}
}
}
```
## Filtering notes
- HubSpot's search API has limited support for NOT_EQUAL filters on custom dropdown properties. To exclude "Approved" deals, fetch all high-discount deals and filter client-side.
- The `discount_approval` property returns an empty string when not set, not null.
- Custom property internal names are case-sensitive. Use exactly `discount_percent` and `discount_approval`.Step 4: Test the skill
Invoke the skill conversationally:
/discount-auditClaude will read the SKILL.md, check the reference files, write a script, run it, and report the results. A typical run looks like:
Searching for deals with discounts above 15%...
Found 8 deals with high discounts
Filtered to 5 unapproved deal(s)
Posted summary to Slack
Done. Flagged 5 deal(s) needing discount approval.What the Slack alert looks like
Discount Approval Needed
5 deal(s) have discounts above 15% without approval:
- BrightPath Analytics Platform — $64,000 at 22% discount
- Contoso Platform Deal — $48,000 at 18% discount
- Widget Inc Expansion — $35,000 at 25% discount
Review each deal and update the discount_approval property in HubSpot.
Because the agent generates code on the fly, you can also make ad hoc requests:
- "Which deals have discounts over 20%?" — the agent adjusts the threshold
- "Show me unapproved discounts for the Enterprise pipeline only" — the agent adds a pipeline filter
- "Post to #sales-leadership instead" — the agent changes the target channel
Create or update a deal in HubSpot with discount_percent set to 20 and leave discount_approval empty. Run the skill and verify a Slack message lists that deal. Then set discount_approval to "Approved" and run again — the deal should no longer appear.
Step 5: Schedule it (optional)
Option A: Cron + Claude CLI
# Run every Monday at 9am before deal desk meeting
0 9 * * 1 cd /path/to/your/project && claude -p "Run /discount-audit" --allowedTools 'Bash(*)' 'Read(*)'Option B: GitHub Actions + Claude
name: Discount Audit
on:
schedule:
- cron: '0 14 * * 1' # Every Monday at 9am ET
workflow_dispatch: {} # Manual trigger for testing
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
prompt: "Run /discount-audit"
allowed_tools: "Bash(*),Read(*)"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
HUBSPOT_ACCESS_TOKEN: ${{ secrets.HUBSPOT_ACCESS_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}0 14 * * 1 runs at 2pm UTC, which is 9am ET. GitHub Actions cron may also have up to 15 minutes of delay. For time-sensitive alerting, use cron on your own server or a dedicated scheduler instead.
Option C: Cowork Scheduled Tasks
Claude Desktop's Cowork supports built-in scheduled tasks. Open a Cowork session, type /schedule, and configure the cadence — hourly, daily, weekly, or weekdays only. Each scheduled run has full access to your connected tools, plugins, and MCP servers.
Scheduled tasks only run while your computer is awake and Claude Desktop is open. If a run is missed, Cowork executes it automatically when the app reopens. For always-on scheduling, use GitHub Actions (Option B) instead. Available on all paid plans (Pro, Max, Team, Enterprise).
Troubleshooting
When to use this approach
- You want periodic audits — "flag all unapproved discounts before the weekly deal desk meeting" — rather than real-time approval flows
- You want conversational flexibility — ad hoc queries like "which deals have discounts over 20%?" alongside scheduled checks
- You're already using Claude Code and want skills that integrate with your workflow
- You want to run tasks in the background via Claude Cowork while focusing on other work
- You prefer guided references over rigid scripts — the agent adapts while staying reliable
When to switch approaches
- You need interactive Approve/Deny buttons with automated HubSpot write-back → use n8n with Send and Wait or the code approach
- You want a no-code setup with a visual builder → use Zapier or Make
- You need real-time notifications the moment a discount is applied → use the code approach with webhooks
This Claude Code skill searches for deals that currently have high unapproved discounts. It doesn't monitor for new discount changes in real time. If you need instant notifications when a rep applies a discount, use the n8n, Zapier, or code approach instead. The skill is best for periodic audits — "what needs approval right now?" — and ad hoc queries.
Common questions
Why not just use a script?
A script runs the same way every time. The Claude Code skill adapts to what you ask — different thresholds, filtered pipelines, summary grouped by rep, a different channel. The reference files ensure it calls the right APIs even when improvising, so you get flexibility without sacrificing reliability.
Does this use Claude API credits?
Yes. Unlike the script-based approach, the agent reads skill files and generates code each time. Typical cost is $0.01-0.05 per invocation depending on how many deals are returned and how much the agent needs to read. The HubSpot and Slack APIs themselves are free.
Can I change the discount threshold without editing files?
Yes. Just tell Claude: "Run /discount-audit with a 20% threshold." The SKILL.md specifies 15% as the default, but the agent can override it based on your request. No file changes needed.
Can I run this skill on a schedule without a server?
Yes. GitHub Actions (Option B in Step 5) runs Claude on a cron schedule using GitHub's infrastructure. The free tier includes 2,000 minutes/month — more than enough for a weekly audit.
Cost
- Claude API — $0.01-0.05 per invocation (the agent reads files and generates code)
- HubSpot API — included in all plans, no per-call cost
- Slack API — included in all plans, no per-call cost
- GitHub Actions (if scheduled) — free tier includes 2,000 minutes/month
Looking to scale your AI operations?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.