Slash commands
An installed app can register slash commands. People run them from the composer's / picker in channels the app was added to, on a computer or a phone. Each time, Missived sends one signed request to the app's interactions URL, and the app answers within 3 seconds.
Set the interactions URL
In Org Settings → Integrations → Apps & bots, open your app and set its interactions URL. It must be public HTTPS. When you save it, Missived sends a signed ping ({ "type": 1 }); answer { "type": 1 }. The panel shows the app's public key (Ed25519, hex) with Copy and Rotate.
Register commands
With the app's token and the commands:write scope:
curl -X PUT https://api.missived.com/v1/orgs/<orgId>/commands \
-H "Authorization: Bearer $MISSIVED_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d '[{ "name": "roll", "description": "Roll dice", "options": [
{ "type": "integer", "name": "sides", "description": "How many sides", "required": false, "min_value": 2, "max_value": 100 } ] }]'
PUTreplaces the whole set;POSTadds one;PATCH /v1/orgs/{orgId}/commands/{commandId}changes one and bumps its version;DELETEremoves it.- Up to 50 commands per install, each optionally limited to one channel.
- Option types: string, integer, number, boolean, user, channel and role, with
required,choicesand bounds. A channel option never offers a direct message. - Who may run a command:
everyone,manage_channeloradmin.
Missived's built-ins (/shrug, /tableflip, /unflip, /me, /gif, /poll) share the same picker.
Verify the request
Each request is a POST with a JSON body and the headers X-Signature-Ed25519 (hex) and X-Signature-Timestamp. The signature covers the timestamp followed by the exact raw body: Discord's scheme, so verifyKey(body, signature, timestamp, publicKey) from discord-interactions works. Verify before parsing, reject stale timestamps, and treat the body's id as a one-time id.
{ "id": "…", "type": 2, "token": "…", "application_id": "…", "org_id": "…",
"channel": { "id", "name", "type" }, "member": { … }, "user": { "id", "name" },
"data": { "name": "roll", "version": 1, "options": [{ "name": "sides", "value": 20 }], "resolved": { … } },
"timestamp": "…" }
The request carries the command and its options, never the surrounding conversation or anyone's email.
Answer
{ "type": 4, "data": { "content": "You rolled 17", "embeds": [] } }posts a reply as the bot.{ "type": 5 }posts a "thinking…" placeholder; finish it later (below).- Add
"flags": 64todatato make the reply private to the person who ran the command. - Replies may carry buttons and menus, or
type: 9opens a form.
No answer within 3 seconds is a failure the person sees; Missived doesn't retry.
Follow-ups and edits
The request's token is valid for 15 minutes and is the only credential these need:
PATCH /v1/interactions/{token}/messages/@originalreplaces the reply or the placeholder.DELETE /v1/interactions/{token}/messages/@originalremoves it.POST /v1/interactions/{token}/messagesposts a follow-up (up to 20). Send anIdempotency-Keyso a retry doesn't post twice.
Removing the app from the channel, pausing it or uninstalling it ends its outstanding tokens.
Limits
- A person may run 20 commands every 10 seconds; an install receives at most 120 a minute.
- 3 seconds to answer; 15 minutes for follow-ups; 20 follow-ups per interaction.
The TypeScript SDK has a receiver that verifies requests and routes commands, components and forms.