Adds five top-level operational tool skills, one per named tool: - slack: messages, channels, threads, search, files, and webhook signature verification (HMAC-SHA256) via a bounded, stdlib-only slack-cli. - notion: pages, database queries, search, and guarded page updates via notion-cli. - email: transactional email via Twilio SendGrid (send, deliverability bounces/spam reports, Signed Event Webhook verification with a self-contained ECDSA P-256 verifier) via email-cli. - crm: HubSpot CRM records, contact search, and deal pipeline views with guarded stage updates via crm-cli. - stripe: read-only-first balance, payment, and subscription queries with a guarded period-end subscription cancellation via stripe-cli. Each skill ships an executable script (--json output, --limit bounded reads, --dry-run/--yes mutation gate), a human README with the five required sections, a schema-v1 evals/evals.json with six output-quality cases, a dated source index + operations reference, and a deterministic unittest suite run by check-artifacts. All five are indexed in the top-level README and the generated catalogs were regenerated. Eval coverage rises from 78/139 to 83/144. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
3.7 KiB
Slack Web API Operations
Last Updated: 2026-08-03
Operational detail for the Slack Web API surface the skill owns: methods, scopes, pagination, error handling, and webhook signature verification. The bundled slack-cli implements this reference; use this document when a call behaves unexpectedly or you need the exact scope/method contract.
Method surface
All calls POST form-encoded fields to https://slack.com/api/<method> with the token as Authorization: Bearer and read the JSON response; ok: false plus error is the error shape.
| Operation | Method | Required scopes | Notes |
|---|---|---|---|
| List channels | conversations.list |
channels:read, groups:read |
types selects public/private/IM/MPIM; exclude_archived filters |
| Read history | conversations.history |
channels:history, groups:history |
Newest first; returns messages + response_metadata.next_cursor |
| Thread replies | conversations.replies |
channels:history, groups:history |
Parent message is the first result; ts is the parent timestamp |
| Post message | chat.postMessage |
chat:write |
Guarded mutation; thread_ts replies in a thread |
| Search messages | search.messages |
search:read |
Supports in:, from:, before:/after:, quoted phrases |
| List files | files.list |
files:read |
Optionally filter by channel or user |
Pagination and bounded reads
- Every listing method returns at most
limitresults per page (max 100 for most) plusresponse_metadata.next_cursor. - Bounded-read rule: request only what the task needs;
slack-cli --limitcaps at the request level. If a task needs more, page explicitly with--cursor, and stop when the question is answered. - Search returns
total(total matches) alongside the boundedmatchesarray — report the total, return only the cap.
Error handling
ok: falsewith anerrorstring:invalid_auth(token bad/expired),missing_scope(token lacks the scope — the exact scope is in the responseneeded/providedfields),channel_not_found,not_in_channel,ratelimited(429 — back off and retry withRetry-After).is_ratelimited: truein a 200 response: the method was throttled; slow down.- Never retry a failed send blindly:
chat.postMessagecan be retried with the sametext(it is not idempotent in the strict sense), so confirm state viaconversations.historybefore re-sending.
Webhook signature verification
Slack signs every outbound HTTP request to your endpoints (events, slash commands, interactivity). Algorithm per Verifying requests from Slack:
- Take the exact raw request body bytes — any re-encoding (JSON pretty-print, charset change) breaks the signature.
- Reject if
|now - X-Slack-Request-Timestamp| > 300seconds (replay window). - Compute
v0=HMAC_SHA256(signing_secret, "v0:" + timestamp + ":" + body). - Compare with
X-Slack-Signatureusing a constant-time comparison (hmac.compare_digest).
The app signing secret lives in the Slack app settings (Basic Information → App Credentials → Signing Secret) and is distinct from the bot token. Never log the secret, the signature comparison, or full webhook bodies; slack-cli webhook verify reports a boolean result.
Token and scope hygiene
- Bot tokens (
xoxb-) act as the app; user tokens (xoxp-) act as a user. Scope needs differ: reading public channels needschannels:history; reading private channels needsgroups:historyon a bot that has been added to the channel. - Store tokens in the environment (
SLACK_TOKEN), never in code, chat, or commit messages. Revoke and rotate a token that leaks — it is a credential, not a config value.