Slack Actions
Slack is where teams triage incidents and coordinate handoffs. VoltOps ships managed Slack actions so you can post messages, send ephemerals, react to messages, and search history without hand-writing Slack REST calls.
Prerequisites​
- Slack app installed with a bot token that has scopes such as
chat:write,chat:write.public,channels:read,groups:read,im:write,users:read, andreactions:write. Invite the bot to the channels you plan to use. - A Volt project (free or paid) with API keys (
pk_…,sk_…). - A Slack credential inside Volt: Settings → Integrations → Add Credential → Slack, paste the
bot token, and save. Volt returns a
cred_xxxidentifier. - (Recommended) Store defaults as environment variables:
SLACK_CREDENTIAL_ID=cred_xxx
SLACK_DEFAULT_CHANNEL_ID=C0123456
SLACK_DEFAULT_THREAD_TS=1720472000.000200
Available actions​
slack.postMessage– send to a channel or DM, supports blocks, attachments, link unfurls, and threads.slack.postEphemeral– send an ephemeral message to a user inside a channel.slack.updateMessage– edit an existing message viamessageTs.slack.deleteMessage– delete a message givenchannelIdandmessageTs.slack.getMessagePermalink– retrieve a permalink for any message.slack.searchMessages– search Slack messages with sort, channel filters, and limits.slack.addReaction/slack.removeReaction/slack.getReactions– manage emoji reactions on a message.
The SDK currently ships helpers for postMessage, deleteMessage, and searchMessages; the other
catalog entries are available from the Volt console today and will be exposed through the SDK as
they graduate.
Running Slack actions from code​
import { VoltOpsClient } from "@voltagent/core";
const voltops = new VoltOpsClient({
publicKey: process.env.VOLTAGENT_PUBLIC_KEY!,
secretKey: process.env.VOLTAGENT_SECRET_KEY!,
});
// Post to a channel (or thread)
await voltops.actions.slack.postMessage({
credential: { credentialId: process.env.SLACK_CREDENTIAL_ID! },
channelId: process.env.SLACK_DEFAULT_CHANNEL_ID!,
text: "Incident resolved ✅",
threadTs: process.env.SLACK_DEFAULT_THREAD_TS ?? undefined,
blocks: [
{
type: "section",
text: { type: "mrkdwn", text: "*Latency* back to normal." },
},
],
linkNames: true,
});
// DM a user by Slack handle and override the credential inline
await voltops.actions.slack.postMessage({
credential: { accessToken: process.env.SLACK_BOT_TOKEN! },
targetType: "user",
userName: "ada",
text: "Shipping a patch in 10 minutes.",
});
// Delete a message that the bot posted
await voltops.actions.slack.deleteMessage({
credential: { credentialId: process.env.SLACK_CREDENTIAL_ID! },
channelId: process.env.SLACK_DEFAULT_CHANNEL_ID!,
messageTs: "1720472000.000200",
});
// Search the workspace
await voltops.actions.slack.searchMessages({
credential: { credentialId: process.env.SLACK_CREDENTIAL_ID! },
query: '"outage" in:C0123456',
sort: "timestamp",
limit: 5,
});
Treat Slack actions as tools​
import { createTool } from "@voltagent/core";
import { VoltOpsClient } from "@voltagent/core";
import { z } from "zod";
const voltops = new VoltOpsClient({
publicKey: process.env.VOLTAGENT_PUBLIC_KEY!,
secretKey: process.env.VOLTAGENT_SECRET_KEY!,
});
export const postSlackUpdate = createTool({
name: "postSlackUpdate",
description: "Post a Slack message to a channel or DM.",
parameters: z.object({
text: z.string(),
channelId: z.string().optional(),
userName: z.string().optional(),
threadTs: z.string().optional(),
}),
execute: async ({ text, channelId, userName, threadTs }) => {
return await voltops.actions.slack.postMessage({
credential: { credentialId: process.env.SLACK_CREDENTIAL_ID! },
channelId: channelId ?? process.env.SLACK_DEFAULT_CHANNEL_ID!,
targetType: userName ? "user" : "conversation",
userName: userName ?? undefined,
text,
threadTs,
linkNames: true,
});
},
});
Agents can add the tool to their toolset to post progress updates, DM owners, or attach reactions as they work through a task.
Testing payloads in the console​
- Open Volt Console → Actions → Add Action and pick the Slack action you want to test.
- Attach the Slack credential and choose defaults (channel/user modes, thread timestamp, etc.).
- Use the Payload & Test editor to try text, blocks, attachments, or reactions; successful runs show the raw Slack response plus a copy-pasteable SDK snippet.
- Use console runs to capture the
messageTsyou need for delete/update/permalink or reaction actions.
Troubleshooting​
channel_not_foundornot_in_channelusually means the bot is not invited to that channel or lackschat:writescope.- DM and ephemeral messages require a
userIdoruserName; ephemeral also needs the channel ID. messageTsvalues come from Slack responses (e.g.,chat.postMessage); reuse them for delete, update, permalink, and reaction actions.- Blocks and attachments must be arrays; if you paste JSON strings, ensure they parse to arrays.
- Custom reactions should omit colons (use
eyesorname:emoji_id). - Check Volt → Actions → Runs to inspect payloads, metadata, retries, and provider errors.