The complete Slack Web API client for Google Apps Script.
From a spreadsheet to Slack in five minutes — no build step, server, or runtime dependency.
5-minute quickstart · Examples · AI guide · API coverage · Issues
English · 日本語 · 简体中文 · 한국어 · Español · Português
GASlacker is a lightweight Slack Web API client designed specifically for the Apps Script V8 runtime.
- 168 Slack Web API methods organized like the official SDKs:
slack.chat.postMessage({...})— full parity with Slack's official SDK method list (minusadmin.*and discontinued APIs) - Bearer authorization + JSON requests, with automatic retry on rate limits (HTTP 429, honoring
Retry-After) - File uploads implemented with the current 3-step external upload flow (
files.uploadV2) - OAuth v2 (
oauth.v2.access) and modern APIs such ascanvases.*/assistant.threads.* - Zero runtime dependencies — a single
bundle.jsfor the GAS V8 runtime - Cursor pagination helper:
slack.paginate('conversations.list', { limit: 200 }, 'get') - Escape hatch for any method:
slack.call('some.method', params) - AI-readable method catalog and a human-approved action pattern
Every endpoint name in this library is verified to exist on the live Slack API
(dead endpoints answer unknown_method; see tests/routing.spec.ts),
and a weekly CI job checks parity against Slack's
official SDK method list — when Slack ships new APIs, an issue is filed automatically.
No build step is required — dist/bundle.js in this
repository is the ready-to-use distributable. Choose one:
A. Add the published library (easiest)
-
In your Apps Script project, open Libraries and add this script ID:
101aZZYpRRnr5AGkVIo8t_yo4kHb7xryLfq3w-HVPpQ4fX0Tkxv3UJyzc -
Pick the latest version, keep the identifier
GASlacker, and callGASlacker.methods(token).
To pin your own copy instead, create a standalone Apps Script project, paste
dist/bundle.js into it, and deploy it as your own library.
B. Paste directly into your project
Copy dist/bundle.js into your Apps Script project as a
script file and call methods(token) directly (no GASlacker. prefix).
C. Push with clasp
Clone this repository, copy the local clasp configuration template, and replace
YOUR_SCRIPT_ID with your own Apps Script project ID:
cp .clasp.example.json .clasp.json
pnpm install
pnpm run deploy # build + clasp pushTo rebuild dist/bundle.js yourself, run pnpm install && pnpm run build
(Node.js 22.12+ and pnpm required).
Save your bot token in Script Properties as SLACK_ACCESS_TOKEN, then:
var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN')
var slack = GASlacker.methods(token)
function hello() {
var res = slack.chat.postMessage({ channel: 'C0123456789', text: 'Hello World' })
if (!res.ok) {
Logger.log(res.error)
}
}Every method returns a response object — check ok / error yourself. Slack JSON responses
are preserved; an exhausted HTTP 429 is normalized as described under rate-limit retries below.
Do not process Slack Events API requests directly in an Apps Script doPost Web App.
Slack requires the raw request body plus the X-Slack-Signature and
X-Slack-Request-Timestamp headers for request verification, but Apps Script does not expose
incoming request headers to doPost(e). A public handler that acts on the JSON body alone can
be forged by anyone who learns its URL.
Receive and verify events in an HTTP service that exposes request headers (for example, Cloud Run or Cloud Functions), acknowledge them within three seconds, and keep GASlacker for outbound Web API calls from trusted Apps Script workflows. See Slack's request verification and Events API documentation.
slack.call('chat.postMessage', { channel: 'C0123456789', text: 'Hi' })
slack.call('conversations.list', { limit: 20 }, 'get')
// Token rotation is form-encoded and must not carry an Authorization header
var tokenFree = GASlacker.methods(null)
tokenFree.call('tooling.tokens.rotate', { refresh_token: refreshToken }, 'form')paginate follows response_metadata.next_cursor until it is empty and returns one response per
page (with the same rate-limit retries as every other call). Pass a positive integer as the
optional fourth argument only when you intentionally want to cap the number of pages:
var pages = slack.paginate('conversations.list', { limit: 200 }, 'get')
var channels = pages.flatMap(function (p) {
return p.channels || []
})files.uploadV2 wraps Slack's 3-step upload flow
(files.getUploadURLExternal → upload → files.completeUploadExternal) in one call:
var blob = Utilities.newBlob('hello', 'text/plain', 'hello.txt')
slack.files.uploadV2({ channel_id: 'C0123456789', file: blob, initial_comment: 'A file!' })
// or upload a string as a file
slack.files.uploadV2({ channel_id: 'C0123456789', content: 'hello', filename: 'hello.txt' })Pass a GAS Blob as file, or a string as content (with filename).
The individual steps are also exposed (slack.files.getUploadURLExternal /
slack.files.completeUploadExternal) if you need finer control.
slack.oauth.access({
client_id: clientId,
client_secret: clientSecret,
code: code,
redirect_uri: redirectUri,
})oauth.access, openid.connect.token, and tooling.tokens.rotate are sent without an
Authorization header because their exchange credentials are in the request body and Slack
rejects an unrelated bearer token. openid.connect.userInfo is the opposite — it needs the
user token the exchange returned, so build a client with it:
GASlacker.methods(userToken).openid.connect.userInfo().
Type definitions are generated into dist/types/. In a
clasp + TypeScript project, copy that folder in and include it in your
tsconfig.json — gas-global.d.ts declares the
GASlacker global (library use) and the methods global (direct paste), so
all 168 methods autocomplete.
GASlacker.methods(token, retriesLimit) — retriesLimit is the number of extra
attempts on HTTP 429 (default 3; integer from 0 to 10; 0 sends exactly one request). Waits
for the Retry-After header between attempts. If every attempt is rate-limited, the method
returns { ok: false, error: 'ratelimited', retry_after: seconds } without sleeping after the
final response. Retry waits are capped at five minutes in total, so a longer single wait or
repeated long waits return that structured response instead of exhausting Apps Script's
execution time.
GASlacker is designed to be the deterministic Slack action layer in an AI-assisted Google Workspace automation. Let a model classify, summarize, or draft; let small Apps Script code apply an explicit destination allowlist, action cap, duplicate protection, and human approval before a consequential Slack write.
docs/ai.mdexplains when to use GASlacker, the official Slack MCP server, or a real-time Slack agent framework.docs/llms.txtgives coding assistants concise, security-oriented project context.docs/methods.jsonlists every wrapper path, endpoint, transport style, conservative effect classification, and official method documentation URL.
The core library intentionally remains model-provider-neutral and has no AI runtime dependency.
Copy-paste-ready scripts live in examples/:
notify-from-spreadsheet.js— daily sheet summary with Block Kitform-response-notification.js— Google Form response → Slack notificationdaily-calendar-agenda.js— every morning's Google Calendar agendaoverdue-task-reminder.js— idempotent overdue-task DMs from a sheetai-approved-draft.js— allowlisted, human-approved AI draftsupload-and-paginate.js— file upload + walking all channels
| Property | Slack API family |
|---|---|
slack.api |
api.test, plus call() / paginate() for arbitrary methods |
slack.apps |
apps.* (incl. connections, event.authorizations, manifest, user) |
slack.assistant |
assistant.threads.* |
slack.auth |
auth.* (incl. teams.list) |
slack.bookmarks |
bookmarks.* |
slack.bots |
bots.* |
slack.calls |
calls.* (incl. participants) |
slack.canvases |
canvases.* (incl. access / sections) |
slack.chat |
chat.* (incl. startStream / appendStream / stopStream) |
slack.conversations |
conversations.* (incl. canvases, Slack Connect invites) |
slack.dialog |
dialog.* (legacy) |
slack.dnd |
dnd.* |
slack.emoji |
emoji.* |
slack.entity |
entity.presentDetails |
slack.files |
files.* (incl. remote, 3-step upload) |
slack.functions |
functions.* |
slack.oauth |
oauth.v2.access |
slack.openid |
openid.connect.* (Sign in with Slack) |
slack.pins |
pins.* |
slack.reactions |
reactions.* |
slack.reminders |
reminders.* |
slack.search |
search.* |
slack.slackLists |
slackLists.* (Lists API) |
slack.stars |
stars.* (superseded by "Later" but still served) |
slack.team |
team.* (incl. profile, billing, preferences, externalTeams) |
slack.tooling |
tooling.tokens.rotate |
slack.usergroups |
usergroups.* (incl. users) |
slack.users |
users.* (incl. profile, setPhoto, discoverableContacts) |
slack.views |
views.* |
slack.workflows |
workflows.featured.* |
Method names mirror Slack's exactly — including delete: chat.delete(),
files.delete(), canvases.delete(). (The older delete_ aliases still work.)
- Legacy
channels.*/groups.*/im.*/mpim.*/rtm.* files.comments.*andapps.permissions.*(discontinued by Slack; they answerunknown_method)files.upload(v1, discontinued) — usefiles.uploadV2admin.*enterprise methods (out of scope; useslack.call()if needed)
pnpm run lint # oxlint
pnpm run typecheck # tsc --noEmit
pnpm run test # vitest
pnpm run catalog # regenerate docs/methods.json from the routing table
pnpm run build # catalog + lint + typecheck + test + vite build
pnpm run deploy # build + clasp pushSee docs/verification.md for the manual verification plan against the real Slack API, and CONTRIBUTING.md for how to add a new API method.
- Slack Web API docs: https://docs.slack.dev/reference/methods/
- Inspired by os/slacker and soundTricker/SlackApp
MIT License. See LICENSE.txt.