moymo,Docs
Skip to content
HTTP API Resources

Message ​

A bot reads and writes messages as itself, with the permissions of its role in the channel. All calls need a bot token.

Message object ​

FieldTypeDescription
idUUID
seqintegerThe order number of the message across the whole service (what history pages by)
channel_idUUID
server_idUUID
authoruserid, username, display_name, avatar, bot
contentstringThe text, up to 4000 characters. Empty when withheld
timestamptime
edited_timestamp?time
typeinteger0 a message, 19 a reply, 20 the answer to a slash command, 21 the answer to a button or a menu
kindstringTEXT, SYSTEM (the server says something: someone joined), POLL or GIVEAWAY
pinnedboolean
mention_everyoneboolean
mentionsarray of stringsThe usernames the text names
mention_rolesarray of UUIDs
reactionsarray{ emoji, count, me }
embeds?arrayEmbeds
components?arrayRows of components
attachmentsarray{ id, filename, content_type, size }. Downloading a file a member attached is not part of the App API yet
flagsintegerMessage flags
application_id?UUIDThe application whose bot wrote it, or answered with it
referenced_message_id?UUIDThe message this one replies to
interaction?object{ type, name, user } when a member caused the message: type is command, component or modal
content_withheldbooleantrue when the bot has no message content intent and this message is not one it may read

A ? before a type marks a field that is left out when it has no value; the API never sends null.

Example messageJSON
json
{
  "id": "9b2f6c1e-7d4a-4e83-a1b5-3c0d8e5f7a21",
  "seq": 18342,
  "channel_id": "2d7c4a90-1b3e-4f58-9a6c-8e0b5d3c7f14",
  "server_id": "5f1d2b8e-7a64-4d07-8d3a-0b9f6c4e2a11",
  "author": {
    "id": "b2a40959-d70f-4cd2-892f-1c037515d8fa",
    "username": "dice_roller",
    "display_name": "Dice Roller",
    "bot": true
  },
  "content": "Rolled **4**",
  "timestamp": "2026-11-03T18:21:07.412Z",
  "type": 0,
  "kind": "TEXT",
  "pinned": false,
  "mention_everyone": false,
  "mentions": [],
  "mention_roles": [],
  "reactions": [{ "emoji": "🎲", "count": 2, "me": false }],
  "embeds": [{ "title": "d6", "color": 3145582 }],
  "attachments": [],
  "flags": 0,
  "application_id": "0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10",
  "content_withheld": false
}

Mentions ​

Mentions are written in the text the way members write them in Moymo for Windows:

WriteTo mention
<@username>A member (3 to 24 lowercase letters, digits and underscores)
<@&role-id>A role (it has to be mentionable, or the bot needs Mention Everyone)
@everyone, @hereEverybody (needs Mention Everyone)
<#channel-id>A channel

Message flags ​

FlagValue
SUPPRESS_EMBEDS1 << 2 (4)Hide the cards made for links
EPHEMERAL1 << 6 (64)Only for interaction responses: only the member who acted sees it. Never stored
LOADING1 << 7 (128)A deferred response that has not been written yet: "App is thinking…". Set by Moymo
SUPPRESS_NOTIFICATIONS1 << 12 (4096)Make no notification for the message

A bot may set SUPPRESS_EMBEDS and SUPPRESS_NOTIFICATIONS when it writes a message; the others are set by Moymo. Flags are stored and returned; clients do not act on SUPPRESS_EMBEDS and SUPPRESS_NOTIFICATIONS yet.

Allowed mentions ​

allowed_mentions says whom the text may really ping. Without it a bot's message may ping everybody its text names (as a person's would); an interaction response may ping members only.

FieldDescription
parseAny of "users", "roles", "everyone": the kinds that may be pinged
usersUp to 100 member ids that may be pinged (do not also parse users)
rolesUp to 100 role ids that may be pinged (do not also parse roles)

An empty object, {}, pings nobody: the text still shows the names, and nobody is notified.

Ping nobody, but still show the namesJSON
json
{
  "content": "Thanks <@ada> and <@&0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10>!",
  "allowed_mentions": {}
}

Embed object ​

An embed is a formatted card inside a message. The shape and the limits are Discord's.

FieldTypeLimit and description
titlestring256 characters
descriptionstring4096 characters
urlstringhttps address the title links to
timestampstringISO 8601 time, shown in the footer
colorinteger0 to 16777215 (0xFFFFFF): the stripe at the edge
footerobject{ text, icon_url }: text up to 2048 characters
imageobject{ url }
thumbnailobject{ url }
authorobject{ name, url, icon_url }: name up to 256 characters
fieldsarrayUp to 25 of { name, value, inline }: name 256, value 1024 characters

A message has up to 10 embeds, and all the text in them (titles, descriptions, field names and values, footers, author names) is at most 6000 characters together. An embed with nothing in it is refused. A key this list does not name (type, video, provider) is ignored.

Every address is https, without a user name in it, and on a host name: pictures are loaded by each member's own program from your server, which is why nothing else is accepted.

Example embedJSON
json
{
  "title": "Hades",
  "description": "A roguelike about escaping the Underworld.",
  "url": "https://moymo.net/games/hades",
  "color": 3145582,
  "fields": [
    { "name": "Hours", "value": "42", "inline": true },
    { "name": "Rating", "value": "9.1", "inline": true }
  ],
  "footer": { "text": "Moymo" }
}

Get channel messages ​

GET/channels/{channel.id}/messages

Returns a page of the channel's history, oldest first.

QueryDescription
limit1 to 50, default 50
beforeA message id: the messages before it
afterA message id: the messages after it

Give before or after, not both. Without READ_HISTORY the answer is empty. Messages in forum posts are not in this list.

RequestGET/channels/{channel.id}/messages
bash
curl "https://moymo.net/api/app/v1/channels/$CHANNEL_ID/messages?limit=2" \
  -H "Authorization: Bot $MOYMO_BOT_TOKEN"
js
const response = await fetch(`https://moymo.net/api/app/v1/channels/${channelId}/messages?limit=2`, {
  headers: { Authorization: `Bot ${process.env.MOYMO_BOT_TOKEN}` }
})
const messages = await response.json()
python
import os
import requests

response = requests.get(
    f"https://moymo.net/api/app/v1/channels/{channel_id}/messages",
    params={"limit": 2},
    headers={"Authorization": f"Bot {os.environ['MOYMO_BOT_TOKEN']}"},
)
messages = response.json()
Response200OKJSON
json
[
  {
    "id": "4c8e1a7b-2f90-4d36-b5e1-7a3c9d0f6e82",
    "seq": 18340,
    "channel_id": "2d7c4a90-1b3e-4f58-9a6c-8e0b5d3c7f14",
    "server_id": "5f1d2b8e-7a64-4d07-8d3a-0b9f6c4e2a11",
    "author": {
      "id": "1f0c8d64-2a37-4f5b-9a0e-7c4d3b2e1a90",
      "username": "ada",
      "display_name": "Ada",
      "bot": false
    },
    "content": "Anyone up for a game tonight?",
    "timestamp": "2026-11-03T18:19:42.108Z",
    "type": 0,
    "kind": "TEXT",
    "pinned": false,
    "mention_everyone": false,
    "mentions": [],
    "mention_roles": [],
    "reactions": [{ "emoji": "πŸ‘", "count": 3, "me": false }],
    "attachments": [],
    "flags": 0,
    "content_withheld": false
  },
  {
    "id": "9b2f6c1e-7d4a-4e83-a1b5-3c0d8e5f7a21",
    "seq": 18342,
    "channel_id": "2d7c4a90-1b3e-4f58-9a6c-8e0b5d3c7f14",
    "server_id": "5f1d2b8e-7a64-4d07-8d3a-0b9f6c4e2a11",
    "author": {
      "id": "b2a40959-d70f-4cd2-892f-1c037515d8fa",
      "username": "dice_roller",
      "display_name": "Dice Roller",
      "bot": true
    },
    "content": "Rolled **4**",
    "timestamp": "2026-11-03T18:21:07.412Z",
    "type": 0,
    "kind": "TEXT",
    "pinned": false,
    "mention_everyone": false,
    "mentions": [],
    "mention_roles": [],
    "reactions": [],
    "attachments": [],
    "flags": 0,
    "application_id": "0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10",
    "content_withheld": false
  }
]

Get channel message ​

GET/channels/{channel.id}/messages/{message.id}

A message is only found through the channel it is in. Returns a message object.

Create message ​

POST/channels/{channel.id}/messages

Needs Send Messages in the channel. At least one of content, embeds, components or game is required. Returns the message that was written.

FieldTypeDescription
contentstringUp to 4000 characters
embedsarrayUp to 10 embeds
componentsarrayUp to 5 rows of components
allowed_mentionsobjectWhom the text may ping
reply_toUUIDThe message this one answers. Discord's message_reference: { message_id } works too. Needs Read History
flagsintegerSUPPRESS_EMBEDS, SUPPRESS_NOTIFICATIONS
noncestring or numberUp to 64 characters of letters, digits and _ - . :. A message with a nonce the bot used before is not written again: the earlier one is returned, so a send that was cut off can be tried again safely
gamestringThe slug of a game on Moymo, shown as a card (needs Embed Games)

Fields that are not listed (Discord's tts, sticker_ids, poll) are ignored.

RequestPOST/channels/{channel.id}/messages
bash
curl -X POST "https://moymo.net/api/app/v1/channels/$CHANNEL_ID/messages" \
  -H "Authorization: Bot $MOYMO_BOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Rolled **4**",
    "embeds": [{ "title": "d6", "color": 3145582 }],
    "components": [{
      "type": 1,
      "components": [{
        "type": 2, "style": 1,
        "label": "Roll again", "custom_id": "again"
      }]
    }]
  }'
js
const response = await fetch(`https://moymo.net/api/app/v1/channels/${channelId}/messages`, {
  method: 'POST',
  headers: {
    Authorization: `Bot ${process.env.MOYMO_BOT_TOKEN}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    content: 'Rolled **4**',
    embeds: [{ title: 'd6', color: 3145582 }],
    components: [{
      type: 1,
      components: [{
        type: 2, style: 1,
        label: 'Roll again', custom_id: 'again'
      }]
    }]
  })
})
const message = await response.json()
python
import os
import requests

response = requests.post(
    f"https://moymo.net/api/app/v1/channels/{channel_id}/messages",
    headers={"Authorization": f"Bot {os.environ['MOYMO_BOT_TOKEN']}"},
    json={
        "content": "Rolled **4**",
        "embeds": [{"title": "d6", "color": 3145582}],
        "components": [{
            "type": 1,
            "components": [{
                "type": 2, "style": 1,
                "label": "Roll again", "custom_id": "again",
            }],
        }],
    },
)
message = response.json()
Response200OKJSON
json
{
  "id": "9b2f6c1e-7d4a-4e83-a1b5-3c0d8e5f7a21",
  "seq": 18342,
  "channel_id": "2d7c4a90-1b3e-4f58-9a6c-8e0b5d3c7f14",
  "server_id": "5f1d2b8e-7a64-4d07-8d3a-0b9f6c4e2a11",
  "author": {
    "id": "b2a40959-d70f-4cd2-892f-1c037515d8fa",
    "username": "dice_roller",
    "display_name": "Dice Roller",
    "bot": true
  },
  "content": "Rolled **4**",
  "timestamp": "2026-11-03T18:21:07.412Z",
  "type": 0,
  "kind": "TEXT",
  "pinned": false,
  "mention_everyone": false,
  "mentions": [],
  "mention_roles": [],
  "reactions": [],
  "embeds": [{ "title": "d6", "color": 3145582 }],
  "components": [{
    "type": 1,
    "components": [{
      "type": 2,
      "style": 1,
      "label": "Roll again",
      "custom_id": "again"
    }]
  }],
  "attachments": [],
  "flags": 0,
  "application_id": "0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10",
  "content_withheld": false
}

Mentions ping people

A bot's message pings the members and roles its text names, as a person's would (@everyone and roles that are not mentionable need Mention Everyone). Send allowed_mentions whenever the text comes from somebody else (a member's input, a web page), so nobody can make the bot ping a whole server.

Edit message ​

PATCH/channels/{channel.id}/messages/{message.id}

Changes a message the bot wrote. Fields you leave out stay as they were; embeds: [] or components: [] removes them. A message must keep some content, embeds, components, a file or a game. Returns the changed message.

RequestPATCH/channels/{channel.id}/messages/Shell
bash
curl -X PATCH "https://moymo.net/api/app/v1/channels/$CHANNEL_ID/messages/$MESSAGE_ID" \
  -H "Authorization: Bot $MOYMO_BOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "content": "Rolled **6**", "components": [] }'

Delete message ​

DELETE/channels/{channel.id}/messages/{message.id}

The bot's own message, or any message with Manage Messages.

Response204No Content

Create reaction ​

PUT/channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me

Needs Add Reactions. {emoji} is a unicode emoji (URL-encoded) or one of the server's own, written as :name~code:. A message holds up to 20 different reactions.

RequestPUT/channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@meShell
bash
# 🎲, URL-encoded
curl -X PUT \
  "https://moymo.net/api/app/v1/channels/$CHANNEL_ID/messages/$MESSAGE_ID/reactions/%F0%9F%8E%B2/@me" \
  -H "Authorization: Bot $MOYMO_BOT_TOKEN"
Response204No Content

Delete own reaction ​

DELETE/channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me

Takes the bot's reaction back. 204.

Pins ​

GET/channels/{channel.id}/pins
PUT/channels/{channel.id}/pins/{message.id}
DELETE/channels/{channel.id}/pins/{message.id}

Pinning needs Manage Messages. A channel has up to 50 pinned messages. The list is an array of messages; pinning and unpinning answer 204.

The wiki is for Moymo's members and developers. Something wrong or missing? Use "Suggest a change" on any page.