Claude Code x SaaS Integration Guide: Notion, Slack, Linear, GitHub, Figma
A hands-on guide to driving your everyday SaaS stack directly from Claude Code. Full working code and real-world patterns for the five biggest SaaS integrations.
Still thinking of Claude Code as just a code editor? Hook it up to the SaaS tools you use every day and it becomes a full-blown “work orchestrator”. Write a Notion page, post to Slack, file a Linear ticket, open a GitHub PR, pull values from Figma — all from a single natural-language prompt.
In this article we walk through the five SaaS integration patterns we actually use to run ClaudeCodeLab, complete with working code and setup steps. By the end you will have your own personal automation hub.
The three basic integration architectures
There are essentially three ways to connect Claude Code to a SaaS product:
| Approach | Implementation cost | Flexibility | Best for |
|---|---|---|---|
| MCP server | Medium | High | Frequent integrations, reused across projects |
| CLI wrapper | Low | Medium | One-off scripts, simple integrations |
| Webhook receiver | High | High | Bidirectional integrations triggered from the SaaS side |
Beginners should start with a CLI wrapper — it is the shortest path. You just let Claude Code call an API through the Bash tool, so all you really need is an API key in an environment variable. Once you are comfortable, the standard move is to promote it into an MCP server.
1. Notion integration: mass-produce pages with AI
Use cases
- Drop meeting minutes straight into Notion
- Auto-generate weekly reports
- Let the AI keep expanding your internal knowledge base
Implementation
// scripts/notion-create-page.mjs
import { Client } from "@notionhq/client";
const notion = new Client({ auth: process.env.NOTION_TOKEN });
async function createPage(databaseId, title, markdown) {
const blocks = markdown.split("\n\n").map((para) => ({
object: "block",
type: "paragraph",
paragraph: {
rich_text: [{ type: "text", text: { content: para } }],
},
}));
const page = await notion.pages.create({
parent: { database_id: databaseId },
properties: {
Name: { title: [{ text: { content: title } }] },
Status: { select: { name: "Draft" } },
},
children: blocks,
});
return page.url;
}
const [, , dbId, title, ...bodyParts] = process.argv;
const url = await createPage(dbId, title, bodyParts.join(" "));
console.log(`Created: ${url}`);
Using it from Claude Code
claude -p "
Read the meeting minutes below and summarize them into three sections
(decisions / action items / next-meeting agenda), then post to
the Notion minutes database:
$(cat ~/inbox/meeting-raw.txt)
Use database_id: abc123...
After posting, send the URL to slack-channel-general.
"
Claude Code calls notion-create-page.mjs through the Bash tool and pipes the resulting URL into Slack — all in a single prompt.
2. Slack integration: automating notifications and posts
Use cases
- Deploy-complete notifications
- Weekly error summary posts
- Formatting long reports into threads
Implementation (Incoming Webhook — the easiest route)
// scripts/slack-notify.mjs
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
const message = process.argv.slice(2).join(" ");
const res = await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: message,
blocks: [
{ type: "section", text: { type: "mrkdwn", text: message } },
],
}),
});
console.log(res.ok ? "✓ Sent" : `✗ ${res.status}`);
Slack Bolt SDK variant (thread replies, DMs, etc.)
// scripts/slack-post-thread.mjs
import { WebClient } from "@slack/web-api";
const client = new WebClient(process.env.SLACK_BOT_TOKEN);
async function postThread(channel, parent, replies) {
const main = await client.chat.postMessage({ channel, text: parent });
for (const reply of replies) {
await client.chat.postMessage({
channel,
text: reply,
thread_ts: main.ts,
});
}
return main.ts;
}
const channel = process.argv[2];
const [parent, ...replies] = process.argv.slice(3);
await postThread(channel, parent, replies);
Real-world usage with Claude Code
claude -p "
Run scripts/deploy.sh.
If it succeeds, post 'Production deploy complete 🚀' to #dev,
and as thread replies send:
1. Commit hash
2. Number of files changed
3. Build duration
If it fails, send a red-highlighted alert to #dev-alerts.
"
3. Linear integration: auto-filing tickets
Use cases
- Turning bug discussions into tickets
- Batch-filing issues from a design review
- Splitting code review comments into discrete tasks
Implementation
// scripts/linear-create-issue.mjs
const LINEAR_API_KEY = process.env.LINEAR_API_KEY;
const LINEAR_TEAM_ID = process.env.LINEAR_TEAM_ID; // e.g. "ENG"
async function createIssue(title, description, priority = 2) {
const query = `
mutation CreateIssue($input: IssueCreateInput!) {
issueCreate(input: $input) {
success
issue { id identifier url }
}
}
`;
const res = await fetch("https://api.linear.app/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: LINEAR_API_KEY,
},
body: JSON.stringify({
query,
variables: {
input: {
teamId: LINEAR_TEAM_ID,
title,
description,
priority, // 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low
},
},
}),
});
const json = await res.json();
return json.data.issueCreate.issue;
}
const [, , title, ...desc] = process.argv;
const issue = await createIssue(title, desc.join(" "), 2);
console.log(`Created: ${issue.identifier} - ${issue.url}`);
Example: bulk-filing from PR reviews
claude -p "
Read every review comment on GitHub PR #234 and, for any comment that
requires a fix, create an individual Linear ticket.
Each ticket should have:
- Title: a short summary of the issue
- Body: original comment + PR URL + filename:line
- Priority: 1 for 'must fix', 3 for 'suggestions'
"
4. GitHub integration: lean on the gh CLI
For GitHub, the gh CLI is dramatically easier than the raw API. Just let Claude Code hit it through the Bash tool.
Key patterns
# Create a PR
gh pr create --title "feat: add cache layer" --body "$(cat desc.md)"
# File an issue
gh issue create --title "Bug: user logout fails" --label "bug,priority-high"
# View PR review
gh pr view 234 --comments
# Check CI status
gh run list --workflow deploy.yml --limit 5
# Cut a release
gh release create v1.2.0 --notes "Changelog here"
Example: incident response
claude -p "
We are seeing 500 errors spiking in production. Walk through these steps:
1. Read the last hour of logs/prod-*.log and extract error patterns
2. Identify the suspect commit from the stack trace using git log
3. Open a PR that reverts that commit (gh pr create)
4. File an incident ticket in Linear
5. Post a status update to #incident-response on Slack
Target: complete within 15 minutes.
"
5. Figma integration: turn designs into code
Use cases
- Reading the component structure of a Figma file
- Converting Figma values (colors, spacing, font sizes) into CSS
- Screenshot-based visual diff testing
Implementation (Figma REST API)
// scripts/figma-extract.mjs
const FIGMA_TOKEN = process.env.FIGMA_TOKEN;
const fileKey = process.argv[2];
const nodeId = process.argv[3];
const res = await fetch(
`https://api.figma.com/v1/files/${fileKey}/nodes?ids=${nodeId}`,
{ headers: { "X-Figma-Token": FIGMA_TOKEN } }
);
const data = await res.json();
const node = data.nodes[nodeId].document;
// Extract colors, typography, and layout
const tokens = {
colors: extractColors(node),
typography: extractTypography(node),
spacing: extractSpacing(node),
};
console.log(JSON.stringify(tokens, null, 2));
function extractColors(node) { /* implementation omitted */ }
function extractTypography(node) { /* implementation omitted */ }
function extractSpacing(node) { /* implementation omitted */ }
Using it from Claude Code
claude -p "
Read nodeId=456:789 (the card component) from Figma file abc123
and implement it as the React component components/Card.tsx.
- Match Tailwind tokens (pick colors from theme.colors)
- Props: children, variant (primary/secondary)
- Also generate a Storybook story
- Use scripts/figma-extract.mjs to pull Figma values as reference
"
Credential management: .env + gitignore is non-negotiable
An iron rule common to every integration:
# .env (NEVER commit this to git)
NOTION_TOKEN=secret_xxx
SLACK_BOT_TOKEN=xoxb-xxx
SLACK_WEBHOOK_URL=https://hooks.slack.com/xxx
LINEAR_API_KEY=lin_api_xxx
LINEAR_TEAM_ID=ENG
FIGMA_TOKEN=figd_xxx
# .gitignore
.env
.env.*
!.env.example
Document it in CLAUDE.md to prevent accidents
## Handling secrets
- Never commit .env
- Read values inside scripts via process.env
- Never include API keys in prompts or output
- Never print the Authorization header in error messages
Five common pitfalls
1. Ignoring rate limits Slack allows one call per second, Notion three per three seconds, and Linear enforces GraphQL complexity limits. Always sleep between batched calls.
async function batchPost(items) {
for (const item of items) {
await postToNotion(item);
await new Promise((r) => setTimeout(r, 500)); // 500ms spacing
}
}
2. Skipping webhook signature verification When you build a webhook receiver, skipping signature verification opens you up to replay attacks. Both Slack and GitHub publish their signing schemes — always implement them.
3. Forgetting whose permissions are used It is easy to post as a bot and then be surprised that your name does not appear. Document permission scopes in the README.
4. Duplicate execution on retry A network blip triggers a retry and suddenly you have three identical pages in Notion. Use an idempotency key to guarantee at-most-once behavior.
5. No fallback when services go down If Slack is down, your deploy notification is lost and manual ops go unattended. Set up two primary notification paths (e.g., Slack + email) for peace of mind.
Putting it together: five services driven by a single prompt
The endgame. A multi-SaaS workflow in one shot:
claude -p "
Prep this week's release:
1. Extract unreleased commits on master with gh log
2. Generate release notes in Markdown
3. Create a new page in the Notion 'Releases' database
4. Count issues closed this week in Linear
5. Export 5 screenshots of the changes from the Figma 'v2.0 Design' page
6. Post a Slack summary to #team
(summary in 3 lines, details in the thread)
7. Run gh release create v2.0.0 for the official release
Report a concise log of each step.
"
If this works, the weekly release process that used to take an hour becomes a 5-minute hands-off task for Claude Code.
Summary
| SaaS | Quickest integration | Advanced form |
|---|---|---|
| Notion | CLI wrapper + API | Promote to MCP server |
| Slack | Incoming Webhook | Bolt SDK + thread management |
| Linear | Direct GraphQL calls | Wrap as an MCP tool |
| GitHub | The gh CLI is enough | Combine with Actions |
| Figma | REST API | Plugin + MCP |
Drop the “Claude Code = code-writing tool” mindset and the horizon expands dramatically. Start with Slack Incoming Webhook — it’s the lowest-cost first step, done in 10 minutes. Add Notion or Linear next, and you should be able to automate around 30% of your work.
Related articles
- Complete Guide to Harness Engineering
- Claude Code x Obsidian Integration Guide
- 10 Claude Code Subagent Patterns
References
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
Free PDF: Claude Code Cheatsheet in 5 Minutes
Just enter your email and we'll send you the single-page A4 cheatsheet right away.
We handle your data with care and never send spam.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
Claude Code Security Best Practices: API Keys, Permissions & Production Protection
A practical security guide for using Claude Code safely. From API key management to permission settings, Hooks-based automation, and production environment protection — with working code examples.
7 Claude Code Security Failure Cases | Real Incidents and Prevention
Seven real-world security incidents with Claude Code: .env leaks, production DB drops, billing explosions, and more — each with root cause analysis and prevention code.
Complete Guide to Claude Code Permissions | settings.json, Hooks & Allowlist Explained
A complete guide to Claude Code permissions. Learn allow/deny/ask, automation with Hooks, environment-specific settings.json, and practical patterns—all with working code.