Skip to content

Slash commands

Slash commands let members invoke a Kit from the message box. Declare them in the manifest and give the Kit bot the commands scope:

"bot": { "displayName": { "en": "Deployer" }, "scopes": ["commands", "messages:write"] },
"commands": [
{
"command": "/deploy",
"url": "https://kit.acme.example/ketvia/commands",
"description": { "en": "Deploy a service" },
"usageHint": { "en": "[service]" }
}
]

Names match ^/[a-z][a-z0-9_-]{1,31}$. Ketvia built-ins are reserved and refused in manifests (/remind, /away, /help, /invite, /leave, /me, /mute, /search, /status, /topic, /shrug, /dm, /msg, /ketvia, /kit, /kits).

Each workspace has a command registry. The first installation gets /deploy; a later installation declaring the same name is registered as /<slug>:deploy. A workspace admin can reassign the plain name to another installation (POST /v1/workspaces/{id}/kit-commands/reassign); the previous holder becomes /<slug>:deploy. Commands are unregistered when the Kit is uninstalled.

Typing /deploy web --fast in a composer does not create a message. The composer suggests commands as you type and calls the Kit. Commands work only in channels the Kit bot is a member of: elsewhere the member sees “Add to this channel to use /deploy”. Ketvia sends a signed request to the command’s URL:

{
"type": "slash_command",
"installationId": "0b4f…",
"workspaceId": "7c1e…",
"command": "/deploy",
"text": "web --fast",
"user": { "id": "a7f0…", "locale": "en" },
"conversationId": "d3a9…",
"responseUrl": "https://api.ketvia.com/api/v1/responses/kres_…",
"triggerId": "trg_…",
"locale": "en"
}

command is always the name from your manifest, even when it is registered as /<slug>:deploy.

Answer 2xx within 3 seconds, optionally with { responseType, text, blocks }. The default is ephemeral: only the member sees it, in their own surface. inChannel posts as the Kit bot and needs messages:write. For slow work, return immediately and answer later through the responseUrl (30 minutes, 5 uses; see Interactivity).

const kit = createKitServer({
signingSecret: process.env.KETVIA_SIGNING_SECRET ?? '',
onCommand: async (command) => {
void startDeploy(command.text).then((url) =>
respond(command.responseUrl, { responseType: 'inChannel', text: `Deployed: ${url}` }),
);
return { text: `Deploying ${command.text}…` };
},
});

A retried composer submission (same clientRequestId) never calls your Kit twice. If your Kit fails or times out, the member sees “ didn’t respond” and can retry. Limit: 10 invocations per minute per member and command.