Files
magnus919_agent-skills/slack/references/01-web-api-operations.md
T
Magnus HedemarkGitHubfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
3256a87bcb feat(skill): add collaboration & business-app tool layer (Slack, Notion, email, CRM, payments) (#269)
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>
2026-08-03 20:19:26 -04:00

47 lines
3.7 KiB
Markdown

# 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 `limit` results per page (max 100 for most) plus `response_metadata.next_cursor`.
- **Bounded-read rule:** request only what the task needs; `slack-cli --limit` caps 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 bounded `matches` array — report the total, return only the cap.
## Error handling
- `ok: false` with an `error` string: `invalid_auth` (token bad/expired), `missing_scope` (token lacks the scope — the exact scope is in the response `needed`/`provided` fields), `channel_not_found`, `not_in_channel`, `ratelimited` (429 — back off and retry with `Retry-After`).
- `is_ratelimited: true` in a 200 response: the method was throttled; slow down.
- Never retry a failed send blindly: `chat.postMessage` can be retried with the same `text` (it is not idempotent in the strict sense), so confirm state via `conversations.history` before re-sending.
## Webhook signature verification
Slack signs every outbound HTTP request to your endpoints (events, slash commands, interactivity). Algorithm per [Verifying requests from Slack](https://api.slack.com/authentication/verifying-requests-from-slack):
1. Take the **exact raw request body** bytes — any re-encoding (JSON pretty-print, charset change) breaks the signature.
2. Reject if `|now - X-Slack-Request-Timestamp| > 300` seconds (replay window).
3. Compute `v0=HMAC_SHA256(signing_secret, "v0:" + timestamp + ":" + body)`.
4. Compare with `X-Slack-Signature` using 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 needs `channels:history`; reading private channels needs `groups:history` on 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.