Check for large Salesforce deals using a Claude Code skill

low complexityCost: Usage-based

Prerequisites

Compatible agents

This skill works with any agent that supports the Claude Code skills standard, including Claude Code, Claude Cowork, OpenAI Codex, and Google Antigravity.

Prerequisites
  • One of the agents listed above
  • Salesforce connected app or session token with API access to Opportunities
  • Slack bot with chat:write permission, added to the target channel
Environment Variables
# Salesforce instance URL (e.g. https://yourorg.my.salesforce.com)
SALESFORCE_INSTANCE_URL=your_value_here
# Salesforce access token with API access to Opportunity records
SALESFORCE_ACCESS_TOKEN=your_value_here
# Slack bot token starting with xoxb- (chat:write scope required)
SLACK_BOT_TOKEN=your_value_here
# Slack channel ID starting with C (right-click channel > View channel details)
SLACK_CHANNEL_ID=your_value_here

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:

  • "Check for Salesforce opportunities over $50K created today"
  • "What large deals were created this week?"
  • "Post a summary of today's big deals to #executive-deals"

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 time window, a summary instead of individual posts — the agent adapts without you touching any code.

How it works

The skill directory has three parts:

  1. SKILL.md — workflow guidelines telling the agent what steps to follow, which env vars to use, and what pitfalls to avoid
  2. references/ — Salesforce API patterns (SOQL queries, REST endpoints, response formats) so the agent calls the right APIs with the right parameters
  3. templates/ — 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., /large-sf-deal-alert), 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/large-sf-deal-alert/{templates,references}

This creates the layout:

.claude/skills/large-sf-deal-alert/
├── SKILL.md                          # workflow guidelines + config
├── templates/
│   └── slack-alert.md                # Block Kit template for Slack messages
└── references/
    └── salesforce-opportunities-api.md  # Salesforce API patterns

Step 2: Write the SKILL.md

Create .claude/skills/large-sf-deal-alert/SKILL.md:

---
name: large-sf-deal-alert
description: Check for recently created large Salesforce opportunities and post alerts to Slack
disable-model-invocation: true
allowed-tools: Bash, Read
---
 
## Goal
 
Check for Salesforce opportunities created in a given time window (default: today) with Amount >= $50,000 and post a formatted alert per opportunity to a Slack channel.
 
## Configuration
 
Read these environment variables:
 
- `SALESFORCE_INSTANCE_URL` — Salesforce instance URL, e.g. https://yourorg.my.salesforce.com (required)
- `SALESFORCE_ACCESS_TOKEN` — Salesforce access token with API access (required)
- `SLACK_BOT_TOKEN` — Slack bot token starting with xoxb- (required)
- `SLACK_CHANNEL_ID` — Slack channel ID starting with C (required)
 
Default time window: today (CreatedDate = TODAY). The user may request a different window or threshold.
 
## Workflow
 
1. Validate that all required env vars are set. If any are missing, print which ones and exit.
2. Query Salesforce for opportunities created in the time window with Amount >= threshold using SOQL via the REST API. See `references/salesforce-opportunities-api.md` for the query and endpoint.
3. For each opportunity, post a message to Slack using the Block Kit format in `templates/slack-alert.md`.
4. Print a summary of how many alerts were posted.
 
## Important notes
 
- The default SOQL uses `CreatedDate = TODAY` which returns opportunities created in the current UTC day. Adjust for the user's timezone if they ask.
- Salesforce stores stage names as human-readable text on `StageName` — no ID-to-label mapping is needed.
- Salesforce access tokens expire based on session timeout settings. If the token has expired, the API returns INVALID_SESSION_ID. For long-running automations, use a refresh token flow.
- `SLACK_CHANNEL_ID` must be the channel ID (starts with `C`), not the channel name.
- The Slack bot must be invited to the target channel or `chat.postMessage` will fail with `not_in_channel`.
- `Amount` may be null if the amount hasn't been set on the Opportunity. Filter these out.
- 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:

SectionPurpose
GoalTells the agent what outcome to produce
ConfigurationWhich env vars to read and what defaults to use
WorkflowNumbered steps with pointers to reference files
Important notesNon-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/large-sf-deal-alert/templates/slack-alert.md:

# Slack Alert Template
 
Use this Block Kit structure for each large Salesforce opportunity alert.
 
## Block Kit JSON
 
```json
{
  "channel": "<SLACK_CHANNEL_ID>",
  "text": "New large opportunity: <opportunity_name>",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": ":dart: *New Large Opportunity*\n*<opportunity_name>*\nAmount: $<amount>\nStage: <stage_name>\nOwner: <owner_name>\nAccount: <account_name>"
      }
    },
    {
      "type": "context",
      "elements": [
        {
          "type": "mrkdwn",
          "text": "<<salesforce_link>|View in Salesforce>"
        }
      ]
    }
  ]
}
```
 
## Notes
 
- The top-level `text` field is required by the Slack API as a fallback for notifications and accessibility.
- The Salesforce record link format: `<SALESFORCE_INSTANCE_URL>/lightning/r/Opportunity/<OPPORTUNITY_ID>/view`.
- Format the amount with comma separators (e.g., $175,000 not $175000).
- To customize, you can add fields like close date, created date, or probability.

references/salesforce-opportunities-api.md

Create .claude/skills/large-sf-deal-alert/references/salesforce-opportunities-api.md:

# Salesforce Opportunities API Reference
 
## Query large opportunities created today
 
Use SOQL via the REST API to find opportunities matching the criteria.
 
**Request:**
 
```
GET <SALESFORCE_INSTANCE_URL>/services/data/v59.0/query
Authorization: Bearer <SALESFORCE_ACCESS_TOKEN>
```
 
**Query parameter:**
 
```
q=SELECT Id, Name, Amount, StageName, Account.Name, Owner.Name, CreatedDate FROM Opportunity WHERE CreatedDate = TODAY AND Amount >= 50000
```
 
- `TODAY` is a SOQL date literal meaning the current UTC day. Other options: `YESTERDAY`, `LAST_N_DAYS:7`, `THIS_WEEK`.
- URL-encode the SOQL query when passing as a query parameter.
- Adjust the Amount threshold as needed (e.g., 100000 for $100K).
 
**Response shape:**
 
```json
{
  "totalSize": 2,
  "done": true,
  "records": [
    {
      "attributes": {
        "type": "Opportunity",
        "url": "/services/data/v59.0/sobjects/Opportunity/006XXXXXXXXXXXXXXX"
      },
      "Id": "006XXXXXXXXXXXXXXX",
      "Name": "NovaTech Cloud Infrastructure",
      "Amount": 175000,
      "StageName": "Prospecting",
      "Account": {
        "attributes": { "type": "Account" },
        "Name": "NovaTech Industries"
      },
      "Owner": {
        "attributes": { "type": "User" },
        "Name": "Rachel Nguyen"
      },
      "CreatedDate": "2026-03-05T10:30:00.000+0000"
    }
  ]
}
```
 
## Additional useful fields
 
To include close date or probability, expand the SOQL query:
 
```sql
SELECT Id, Name, Amount, StageName, Account.Name, Owner.Name,
       CloseDate, Probability, CreatedDate
FROM Opportunity
WHERE CreatedDate = TODAY AND Amount >= 50000
```
 
## Notes
 
- Salesforce stores stage names as human-readable text on `StageName`, not internal IDs. No mapping is needed.
- `Amount` is a number (not a string). It may be null if the amount hasn't been set.
- The `done` field indicates whether all results are returned. If `done` is `false`, use the `nextRecordsUrl` to fetch additional pages.
- Salesforce access tokens expire based on session timeout settings. A 401 response with `INVALID_SESSION_ID` means the token has expired.
- Account and Owner are relationship fields — access nested Name via `record["Account"]["Name"]` and `record["Owner"]["Name"]`. Either may be null.

Step 4: Test the skill

Invoke the skill conversationally:

/large-sf-deal-alert

Claude will read the SKILL.md, check the reference files, write a script, run it, and report the results. A typical run looks like:

Checking for large opportunities created today...
  Found 2 opportunity(ies) over $50K
  Posted: NovaTech Cloud Infrastructure — $175,000
  Posted: Meridian Systems Platform License — $92,000
Done. Posted 2 alert(s) to Slack.

What the Slack alert looks like

What you'll get
#executive-deals
Salesforce Botapp9:41 AM

🎯 New Large Opportunity

NovaTech Cloud Infrastructure

Amount: $175,000

Stage: Prospecting

Owner: Rachel Nguyen

Account: NovaTech Industries

View in Salesforce

Because the agent generates code on the fly, you can also make ad hoc requests:

  • "Check for opportunities over $100K created this week" — the agent adjusts the threshold and time window
  • "What large deals were created yesterday?" — the agent uses YESTERDAY instead of TODAY
  • "Post a summary of today's big deals to #sales-leadership" — the agent adapts the output format and channel
Test with a real opportunity

Create an Opportunity in Salesforce with Amount >= $50,000, wait a few seconds, then run the skill. If no opportunities were created today above the threshold, you'll see "No large opportunities found" — which is correct, not an error.

Step 5: Schedule it (optional)

Option A: Cron + Claude CLI

# Run daily at 5 PM to catch the day's large deals
0 17 * * * cd /path/to/your/project && claude -p "Run /large-sf-deal-alert" --allowedTools 'Bash(*)' 'Read(*)'

Option B: GitHub Actions + Claude

name: Large Salesforce Deal Alerts
on:
  schedule:
    - cron: '0 17 * * 1-5'  # Weekdays at 5 PM UTC
  workflow_dispatch: {}       # Manual trigger for testing
jobs:
  alert:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          prompt: "Run /large-sf-deal-alert"
          allowed_tools: "Bash(*),Read(*)"
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          SALESFORCE_INSTANCE_URL: ${{ secrets.SALESFORCE_INSTANCE_URL }}
          SALESFORCE_ACCESS_TOKEN: ${{ secrets.SALESFORCE_ACCESS_TOKEN }}
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
          SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
Salesforce token expiration

Salesforce access tokens expire based on your org's session timeout settings (default: 2 hours). For scheduled automation via GitHub Actions, use a Connected App with JWT bearer flow or a refresh token to obtain fresh access tokens automatically. A static access token will stop working after the session expires.

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 conversational flexibility — ad hoc queries like "what deals over $100K were created this week?" alongside scheduled checks
  • You want on-demand alerts during pipeline reviews or standups, not just automated notifications
  • 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 real-time alerts (under 1 minute latency) → use Salesforce Flow Builder
  • You want a no-code setup with a visual builder → use n8n
  • You need alerts running 24/7 with zero cost and no LLM usage → use Flow Builder (it's free and built into Salesforce)

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, time windows, output formats, channels. 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. The agent reads skill files and generates code each time. Typical cost is $0.01-0.05 per invocation depending on how many opportunities are returned. The Salesforce and Slack APIs themselves are included in their respective plans.

How do I handle Salesforce token expiration?

For on-demand use, generate a fresh token before running the skill. For scheduled runs, use a Connected App with JWT bearer flow or OAuth refresh tokens. Store the refresh logic in a separate script that runs before the skill invocation.

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.

Cost

  • Claude API — $0.01-0.05 per invocation (the agent reads files and generates code)
  • Salesforce API — included in Enterprise, Unlimited, and Developer editions
  • 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.