Skip to main content
API Documentation

Webhooks & Integrations

Build bots, automations and integrations with mssgs webhooks and triggers

Getting Started

With mssgs webhooks you can send messages to channels and build interactive bots that respond to commands.

1

Create a webhook

Go to Server Settings > Integrations and create a new webhook or trigger.

2

Copy the URL

Copy the webhook URL or trigger GUID for your integration.

3

Start building

Send JSON payloads to the webhook URL to post messages.

Two ways to integrate

Incoming Webhooks — Send messages to mssgs from external tools (CI/CD, monitoring, etc.)
Webhook Triggers — Build interactive bots that respond to commands and button clicks.

Incoming Webhooks

Send messages to a channel via a webhook URL. Perfect for CI/CD notifications, monitoring alerts, and other automations.

POST /server/:server_guid/webhook/:channel_guid

Request structure

Send a POST request with your message payload as JSON body. Include your server management token in the token field.

Request Body
{
  "token": "server_management_token",
  "content": "Hello from my integration!",
  "color": "green",
  "title": "My Bot"
}

Simple Format

The simplest way to send a message.

Simple Message
{
  "content": "Server backup completed at 03:00 UTC",
  "color": "green",
  "title": "Backup Bot"
}
Field Type Description
content string Message text required
color string blue, green, orange, red, yellow, purple
title string Title above the message
title_url string Makes the title a clickable link
sub_title string Smaller text below the title
avatar_url string Avatar image URL

Full Format (message_container)

For more control over the message, use the full message_container object.

Full Message Container
{
  "message_container": {
    "type": "embed_message",
    "color": "blue",
    "title": "Order Update",
    "description": "Your order #12345 has been shipped!",
    "title_url": "https://example.com/orders/12345",
    "sub_title": "Estimated delivery: Tomorrow",
    "bot_name": "Order Bot",
    "fields": [
      { "field": "Status", "value": "Shipped" },
      { "field": "Tracking", "value": "ABC123456" }
    ]
  },
  "actions": [...]
}
Field Type Description
type string embed_message (default) or system_message
color string Accent color of the message
title string Title of the message
description string Main text required
title_url string Link behind the title
sub_title string Subtitle text
bot_name string Custom bot name
avatar_url string Avatar image
fields array Key-value fields

Fields

Add structured key-value data to your message.

Fields Array
{
  "fields": [
    { "field": "Status", "value": "Completed" },
    { "field": "Duration", "value": "2m 34s" },
    { "field": "Environment", "value": "Production" }
  ]
}

Webhook Triggers

Webhook triggers let you connect external services to your server. When a user types a matching command (e.g. /help) or clicks an action button, the backend POSTs to your webhook URL. Your webhook responds with JSON to post a message back to the channel.

1

User types a command

A user sends a message starting with your trigger's prefix, e.g. /help

2

mssgs calls your webhook

The backend sends a POST request to your configured webhook URL with the message data.

3

You respond with JSON

Your server returns a JSON response with the message content, embeds and actions.

4

Message appears in channel

mssgs displays the response as a message in the channel.

Request Your Webhook Receives

When a user sends a message that starts with your trigger's trigger_match prefix:

POST {your_webhook_url}
Command Match Request
{
  "server_guid": "abc12345-...",
  "channel_guid": "def67890-...",
  "trigger_match": "/help",
  "message": {
    "id": "d01ZZdef6-xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "content": "/help how do I create a channel?",
    "member_guid": "member-guid-here",
    "user_guid": "user-guid-here",
    "cms": 1234567890123,
    "group_guids": ["group-guid-1", "group-guid-2"]
  },
  "callback_url": "https://mss.gs/api/v1/trigger-callback/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Request via Action Button

When triggered via a trigger:{guid} action button, the content is always "[Action Triggered]" and includes the action's payload:

Action Button Request
{
  "server_guid": "abc12345-...",
  "channel_guid": "def67890-...",
  "trigger_match": "/help",
  "message": {
    "id": "d01ZZdef6-xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "content": "[Action Triggered]",
    "member_guid": "member-guid-here",
    "user_guid": "user-guid-here",
    "cms": 1234567890123,
    "group_guids": ["group-guid-1", "group-guid-2"],
    "is_action_button": true,
    "action_payload": {
      "custom_key": "custom_value"
    }
  },
  "callback_url": "https://mss.gs/api/v1/trigger-callback/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Request Fields

Field Type Description
server_guid string The server where the trigger was fired
channel_guid string The channel where the message was sent
trigger_match string The prefix that matched (e.g. /help)
message object The original message that triggered the webhook
message.id string Unique message ID
message.content string Full message text (command match) or "[Action Triggered]" (action button)
message.member_guid string The server member who triggered it
message.user_guid string The user's global GUID
message.group_guids array The server group GUIDs the member belongs to (use to check roles like admin)
message.cms number Timestamp in milliseconds
message.is_action_button boolean true when triggered via an action button (not present for command matches)
message.action_payload object Custom data from the action button (only present for action triggers)
callback_url string Unique URL to update or delete the response message (valid for 30 minutes)

Response Format

Your webhook must respond with 200 status and a JSON body. The response becomes a message in the channel.

Simple response

Simple Response
{
  "content": "Hello! How can I help you?"
}

Embed response

Embed Response
{
  "message_container": {
    "type": "embed_message",
    "color": "blue",
    "title": "Help",
    "description": "Here's how to create a channel...",
    "title_url": "https://docs.example.com/channels",
    "sub_title": "Channel Guide",
    "avatar_url": "https://example.com/bot-avatar.png"
  }
}

Full response with actions

Full Response
{
  "content": "Here's what I found:",
  "message_container": {
    "type": "embed_message",
    "color": "green",
    "title": "Search Results",
    "description": "Found 3 matching items.",
    "title_url": "https://example.com/results",
    "sub_title": "Query: channels",
    "avatar_url": "https://example.com/bot-avatar.png"
  },
  "actions": [
    {
      "type": "button",
      "text": "View Details",
      "color": "blue",
      "triggers": [
        {
          "action": "ws:send",
          "payload": {
            "method": "USER_REQUESTED_TRIGGER",
            "server_guid": "server-guid",
            "channel_guid": "channel-guid",
            "trigger_guid": "details-trigger-guid",
            "action": { "result_id": "42" }
          }
        }
      ]
    },
    {
      "text": "Open Docs",
      "type": "url:https://docs.example.com"
    }
  ]
}

Response Fields

Field Type Description
content string Plain text message content
message_container object Rich embed/system message display
message_container.type string embed_message (default) or system_message
message_container.color string blue, green, orange, red (default: blue)
message_container.title string Embed title
message_container.description string Embed body text
message_container.title_url string Makes the title a clickable link
message_container.sub_title string Smaller text below the title
message_container.avatar_url string Avatar image URL shown alongside the embed
actions array Action buttons (see Actions)

At least one of content, message_container, or actions must be present — otherwise no message is created.

The message author is your trigger's post_app_name (configured in server settings). If not set, the server name is used.

Timeout

Your webhook must respond within 5 seconds. If it times out, an error message is shown to the user. Use the callback URL if you need more time to process.

Actions

Actions are interactive buttons displayed below your message. There are two styles: simple shorthands and trigger chains.

Action Fields

Field Type Description
type string "button" for trigger chains, or shorthand "trigger:{guid}" / "url:{url}" required
text string Button display text (also accepts label) required
color string green, blue, purple (primary) or red, orange, yellow (secondary)
payload object Data passed back when using trigger:{guid} shorthand
triggers array Sequential trigger chain (for type: "button")

Simple Shorthands

For basic actions, use the type shorthand:

Type Description
trigger:{guid} Fires another webhook trigger by its GUID. The trigger receives message.action_payload with the action's payload.
url:{url} Opens the URL in the user's browser
Shorthand Actions
{
  "actions": [
    {
      "text": "Check Status",
      "type": "trigger:abc123-trigger-guid",
      "payload": { "order_id": "12345" }
    },
    {
      "text": "View Order",
      "type": "url:https://example.com/orders/12345"
    }
  ]
}

What happens when an action is clicked?

When the user clicks "Check Status", the target trigger's webhook receives a new request with message.content set to "[Action Triggered]", message.is_action_button set to true, and message.action_payload set to { "order_id": "12345" }.

Trigger Chains

For richer interactions, use type: "button" with a triggers array. Triggers execute sequentially and support conditional logic based on the previous trigger's result.

Trigger types

Action Description
ws:send Sends a WebSocket command to the gateway. Put the method and payload in payload.
local:update_message Updates the message locally (no server round-trip). Provide message_container and optionally actions.
local:remove_message Removes the message from the client's view.

Conditions

Condition Description
(none) Always executes
previous:success Only if the previous trigger succeeded
previous:failed Only if the previous trigger failed

Example: Trigger chain with conditions

This button fires a webhook trigger, then updates the message to show a "processing" state on success, or an error on failure:

Trigger Chain Example
{
  "message_container": {
    "title": "Order #12345",
    "description": "Your order is being processed."
  },
  "actions": [
    {
      "type": "button",
      "text": "Check Status",
      "color": "green",
      "triggers": [
        {
          "action": "ws:send",
          "payload": {
            "method": "USER_REQUESTED_TRIGGER",
            "server_guid": "server-guid",
            "channel_guid": "channel-guid",
            "trigger_guid": "status-check-trigger-guid",
            "action": { "order_id": "12345" }
          }
        },
        {
          "condition": "previous:success",
          "action": "local:update_message",
          "message_container": {
            "color": "blue",
            "title": "Order #12345",
            "description": "Checking status..."
          },
          "actions": []
        },
        {
          "condition": "previous:failed",
          "action": "local:update_message",
          "message_container": {
            "color": "red",
            "title": "Order #12345",
            "description": "Could not check status. Try again later."
          }
        }
      ]
    },
    {
      "type": "button",
      "text": "Dismiss",
      "color": "red",
      "triggers": [
        {
          "action": "local:remove_message"
        }
      ]
    }
  ]
}

What happens when "Check Status" is clicked

1. The client sends USER_REQUESTED_TRIGGER via WebSocket
2. On success: the message updates locally to show "Checking status..." with buttons removed
3. On failure: the message updates to show a red error
4. The webhook fires and its response arrives as a new MESSAGE_CREATE

Rate limit

Users are rate-limited to prevent spam when firing triggers.

Callback URL

Every webhook request includes a callback_url — a unique, token-authenticated URL that your service can call to update or delete the response message after it was posted. The URL is valid for 30 minutes.

Use cases

  • Updating a "processing..." message with final results
  • Showing live progress (e.g. build status, deployment)
  • Removing a message after it's no longer relevant

Update Message

PUT {callback_url}
Update Request
{
  "content": "Updated text content",
  "message_container": {
    "color": "green",
    "title": "Build Complete",
    "description": "All 42 tests passed."
  },
  "actions": []
}

All fields are optional — only include the ones you want to change. To remove action buttons, send "actions": [].

Delete Message

DELETE {callback_url}

No request body needed. The message is permanently deleted from the channel.

Responses

Callback Responses
// 200 OK
{ "success": true }

// 404 Not Found (callback token expired or invalid)
{ "error": "TOKEN_NOT_FOUND" }

// 400 Bad Request (no update fields provided)
{ "error": "MISSING_FIELDS" }

Example: Progress Updates

Progress Update Flow
// 1. Your webhook responds immediately with a "loading" message
// Response:
{
  "message_container": {
    "color": "blue",
    "title": "Deploying...",
    "description": "Starting deployment to production."
  }
}

// 2. Your service updates the message as progress continues
// PUT {callback_url}
{
  "message_container": {
    "color": "blue",
    "title": "Deploying...",
    "description": "Step 2/3: Running migrations."
  }
}

// 3. Final update when done
// PUT {callback_url}
{
  "message_container": {
    "color": "green",
    "title": "Deploy Complete",
    "description": "v2.1.0 is now live on production."
  },
  "actions": [
    {
      "label": "View Logs",
      "type": "url:https://example.com/deploys/123/logs"
    }
  ]
}

Callback URL lifetime

Valid for 30 minutes from when the trigger fires. After that, update/delete requests return 404. Once you delete the message, the callback URL is consumed and cannot be used again.

Errors

When errors occur, you receive a JSON error response.

Error Response
{
  "error": "ERROR_CODE"
}

Error codes

Code Description
INVALID_TOKEN Invalid authentication token
MISSING_REQUIRED_FIELDS Required fields are missing in data
MISSING_CONTENT Message requires content or message_container.description
TOKEN_NOT_FOUND Callback token expired or invalid
MISSING_FIELDS No update fields provided in callback request
UNSUPPORTED_GITHUB_EVENT GitHub event type not supported
UNSUPPORTED_UNIFI_PROTECT_EVENT UniFi Protect event not supported

Success response

Success
{
  "success": true
}

Examples

Simple notification

cURL
curl -X POST https://mss.gs/server/SERVER_GUID/webhook/CHANNEL_GUID \
  -H "Content-Type: application/json" \
  -d '{
    "token": "your_token",
    "content": "Build completed successfully!"
  }'

Colored alert with link

JSON Body
{
  "token": "your_token",
  "content": "Build #123 completed!",
  "color": "green",
  "title": "CI/CD Pipeline",
  "title_url": "https://github.com/org/repo/actions/runs/123"
}

Error alert

JSON Body
{
  "token": "your_token",
  "message_container": {
    "type": "system_message",
    "color": "red",
    "title": "Alert: Database Error",
    "description": "Connection failed: timeout after 30s",
    "sub_title": "prod-db-01"
  }
}

Deployment approval with actions

JSON Body
{
  "token": "your_token",
  "message_container": {
    "color": "yellow",
    "title": "Deployment Request",
    "description": "User @johndoe requested a deployment to production."
  },
  "actions": [
    {
      "label": "Approve",
      "type": "trigger:approve-deploy-trigger-guid",
      "payload": { "deploy_id": "dep_123", "env": "production" }
    },
    {
      "label": "Reject",
      "type": "trigger:reject-deploy-trigger-guid",
      "payload": { "deploy_id": "dep_123" }
    },
    {
      "label": "View Changes",
      "type": "url:https://github.com/org/repo/compare/main...deploy"
    }
  ]
}

Trigger response: private message

Private Response
{
  "message_container": {
    "description": "This is a private response only you can see."
  },
  "visible_to_member_guids": ["<member_guid from request>"],
  "ephemeral": true
}

Trigger response: interactive menu

Interactive Menu
{
  "message_container": {
    "title": "What would you like to do?",
    "description": "Choose an option below:"
  },
  "actions": [
    {
      "label": "Get Help",
      "type": "trigger:help-trigger-guid"
    },
    {
      "label": "View Stats",
      "type": "trigger:stats-trigger-guid",
      "payload": { "period": "weekly" }
    }
  ]
}

Special Webhooks

mssgs automatically recognizes certain webhook types.

GitHub Webhooks

Automatically detected via the x-github-event header. Supported events: Push, Pull Requests, Issues, Releases, and more.

UniFi Protect Webhooks

Automatically detected via user-agent: protect-alarm-manager header.

Notes

  • Timeout: Your webhook must respond within 5 seconds. If it times out, an error message is shown to the user. Use the callback URL if you need more time to process.
  • Message persistence: Trigger response messages are saved to the database and appear in channel history.
  • Callback URL lifetime: Valid for 30 minutes from when the trigger fires. After that, update/delete requests return 404.
  • Rate limiting: Users are rate-limited to prevent spam when firing triggers.

Questions?

We're happy to help you with your integration.

developers@mss.gs