Skip to content

Interactivity

Messages a Kit bot posts (Web API with a bot token, incoming webhooks, interaction and command responses) can contain interactive Blocks: buttons, static selects, overflow menus and section accessories. Declare where clicks go:

"interactivity": { "url": "https://kit.acme.example/ketvia/interactivity" }

Without an interactivity URL, interactive elements are removed from the messages you post (there is nobody to send a click to). Assistant result cards never carry Kit buttons, and approval buttons are Ketvia’s own and never Kit interactions.

  1. A member clicks. The client sends only which element (messageId, blockId, actionId, and for selects the chosen option). Values come from the stored Blocks, never from the client: a button’s value is read from the message, a select’s choice must be one of its stored options. Anything else is a 404.
  2. Ketvia checks that the member can see the message, then sends a signed block_action to your URL:
{
"type": "block_action",
"installationId": "0b4f…",
"workspaceId": "7c1e…",
"actionId": "approve",
"blockId": "act",
"value": "deploy-1234",
"user": { "id": "a7f0…", "locale": "en" },
"container": {
"kind": "message",
"conversationId": "d3a9…",
"messageId": "e1c2…",
"ephemeralId": null
},
"responseUrl": "https://api.ketvia.com/api/v1/responses/kres_…",
"triggerId": "trg_…"
}

triggerId is reserved for modals (not available yet). The request is signed like events.

  1. You have 3 seconds to answer 2xx. If you do not, the member sees “ didn’t respond”. The body may be empty or a response:
{
"replaceOriginal": true,
"text": "Approved",
"blocks": [{ "type": "header", "text": "Approved" }]
}
Field Meaning
responseType ephemeral (default, only the clicking member sees it) or inChannel (a Kit bot message; needs messages:write).
text, blocks The message. text is required with blocks.
replaceOriginal Edit the message the Kit bot authored (or the ephemeral message that was clicked). Needs messages:write for messages.
deleteOriginal Delete it.

Asking for more than the Kit may do (a missing scope, a bot that was removed from the channel) is ignored in the immediate answer and refused with 403 on the responseUrl.

Answer later with POST https://api.ketvia.com/api/v1/responses/{token} and the same JSON. The token is the credential (no Authorization header): it is valid for 30 minutes and 5 uses, bound to one member and one conversation, stored only as a hash and redacted from logs. Unknown, malformed, expired and exhausted tokens all answer 404. A member who left the conversation can no longer receive answers.

import { respond } from '@ketvia/kit';
await respond(action.responseUrl, { text: 'Deploy finished', responseType: 'inChannel' });

POST /api/v1/messages/ephemeral (bot token, scope messages:write.ephemeral) sends a message that exactly one member of a channel the Kit bot was added to can see:

{ "conversationId": "d3a9…", "userId": "a7f0…", "text": "Only you can see this", "blocks": [] }

It is never stored as a normal message: other members, history, search, exports and events never include it. It is delivered to the recipient by a realtime hint plus a fetch, expires after 24 hours and can be dismissed. A recipient who is not a member of the conversation, or a channel the bot is not in, is a 404. Ephemeral messages may carry interactive Blocks; a click on one reaches your URL with container.kind: "ephemeral".

30 interactions per minute per member and Kit. Link buttons (url) never reach the Kit: they open after Ketvia’s “Leaving Ketvia” confirmation.