---
title: "Slash commands: add /commands to your mssgs community"
description: "Give your mssgs community its own slash commands. mssgs sends the message to your web service and posts your JSON answer as a card. Setup, request, reply, private replies, timing and limits."
canonical: https://mss.gs/en/docs/commands
language: en
---

# Add slash commands

Give your community its own /commands . When a member types one, mssgs sends the message to your web service and posts what it answers: a card, buttons, a reply only they can see.

## What you can do

- **Answer with a card** Reply with JSON and it appears in the channel as a card.

- **Know who asked** You get the member and their roles, so you can check who may do what.

- **Reply privately** Show the answer only to the member who asked.

- **Take your time** Answer with a loader in 5 seconds, then finish through the callback URL.

In the app

Type / and the community's commands appear

#### Amsterdam

Your service answers, mssgs posts the card

The picker and the card are the app's own. The footer says who used which command.

- [Quick start](#quick-start)

- [Settings](#settings)

- [What you receive](#request)

- [What you answer](#reply)

- [Five seconds](#timing)

- [Private replies](#private)

- [A full example](#example)

- [Limits](#limits)

## Quick start

- 1 Create the trigger In the desktop app, open your community's **Manage Server → Triggers** and add one: the command it reacts to, such as /weather , and the URL of your web service.

### Receive the message

When a member sends a message that starts with /weather , mssgs POSTs it to your URL:

```json
{
  "server_guid": "abc12345-...",
  "channel_guid": "def67890-...",
  "trigger_match": "/weather",
  "message": {
    "id": "d01ZZdef6-...",
    "content": "/weather Amsterdam",
    "member_guid": "member-guid",
    "user_guid": "user-guid",
    "group_guids": ["group-guid-1", "group-guid-2"],
    "cms": 1790000000000
  },
  "callback_url": "https://mss.gs/api/v1/trigger-callback/...",
  "stream_url": "https://mss.gs/api/v1/instant/...?token=..."
}
```

### Answer with JSON

Answer within 5 seconds with a 2xx status and JSON. It becomes a card in the channel.

```json
{
  "message_container": {
    "color": "blue",
    "title": "Amsterdam",
    "description": "14 °C, light rain until 16:00",
    "fields": [
      { "field": "Wind", "value": "SW 18 km/h" },
      { "field": "Humidity", "value": "82%" }
    ]
  }
}
```

#### Amsterdam

## Settings

Each trigger has these settings in **Manage Server → Triggers**.

| Setting | What it does |
| --- | --- |
| Trigger Name | What the trigger is called, shown next to the command in the picker. |
| Word to Match | The text a message has to start with, such as /weather . A slash is usual, not required. |
| URL Endpoint | Where mssgs sends the message. |
| Webhook Secret | Optional. mssgs signs every request with it, see below. |
| Active | Switch the trigger off without deleting it. |
| Post Matching Message | Whether the member's own /weather Amsterdam stays in the channel above your answer. |
| Show Loading Reply | Show a loading card while your service works. |
| Allowed User Groups | Only members of these roles fire it. For anyone else it is an ordinary message. |

## What you receive

A POST with a JSON body. The headers include User-Agent: mssgs-webhook/1.0 .

| Field | Type | What it is |
| --- | --- | --- |
| server_guid | string | The community. |
| channel_guid | string | The channel the message was sent in. |
| trigger_match | string | The command that matched, such as /weather . |
| message.content | string | The whole message, command included. |
| message.member_guid | string | The member who sent it, in this community. |
| message.user_guid | string | The same person's account, the same in every community. |
| message.group_guids | array | The roles the member has. |
| message.cms | number | When it was sent, in milliseconds. |
| message.is_action_button | boolean | true when a button fired the trigger, not a typed command. |
| message.action_payload | object | The button's payload , for button presses. |
| callback_url | string | Update or delete your answer later, for 30 minutes. |
| stream_url | string | A live stream of replies, reactions and button presses on your answer, for 10 minutes. |

### Checking who may do what

Compare message.group_guids with the roles you trust, for example to let only moderators run /ban . To keep a command away from everyone else entirely, set its roles in the trigger's settings.

## What you answer

Any 2xx status with a JSON body, up to 4 MB. Send at least one of message_container or actions .

| Field | Type | What it is |
| --- | --- | --- |
| message_container | object | The card. Every field on message cards works here, including the status pill, badge, diff stats and folded reasoning. |
| title , description , color , ... | string | Shorthand: card fields at the top level are wrapped into a card for you. |
| actions | array | Buttons under the card. See buttons. |
| visible_to_member_guids | array | Only these members see the answer. See private replies. |

## Five seconds

mssgs waits 5 seconds for your answer. If you need longer, answer straight away with a loader card and finish through callback_url , which stays valid for 30 minutes.

```javascript
// Answer within 5 seconds with a loader...
res.json({ message_container: { loader: true, loader_text: 'Looking it up…' } });

// ...then finish in your own time with the callback URL.
await fetch(req.body.callback_url, {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ message_container: { color: 'blue', title: 'Done', description: result } })
});
```

## Private replies

Put member ids in visible_to_member_guids and only they see your answer. Use the member_guid from the request to answer only the person who asked.

```json
{
  "message_container": {
    "color": "green",
    "title": "You're on the list",
    "description": "Only you can see this reply."
  },
  "visible_to_member_guids": ["<message.member_guid from the request>"]
}
```

## A full example

A /weather command in Node.js with Express, answering with a card.

```javascript
import express from 'express';

const app = express();
app.use(express.json());

app.post('/mssgs/weather', async (req, res) => {
  const city = req.body.message.content.replace('/weather', '').trim() || 'Amsterdam';
  const w = await getWeather(city); // your own lookup

  res.json({
    message_container: {
      color: 'blue',
      title: city,
      description: `${w.temp} °C, ${w.summary}`,
      fields: [
        { field: 'Wind', value: w.wind },
        { field: 'Humidity', value: `${w.humidity}%` }
      ]
    }
  });
});

app.listen(3000);
```

## Limits

| Limit | Value |
| --- | --- |
| Time to answer | 5 seconds |
| Answer size | 4 MB |
| Commands per member | 5 every 5 seconds |
| Updating the answer afterwards | 30 minutes, through callback_url |
| Live stream of the answer | 10 minutes, through stream_url |

## Keep building
