POST
/api/servers/{id}/bots
Create a bot in a server. Caller must be a server member with manage_bots.
Parameters
| Name | In | Required | Type | Description |
|---|
id | path | required | string | Server ID. |
Request Body
application/json
default
{
"name": "Ops Bot",
"default_channel_id": "ch_6fb77a2e"
}
Responses
201 Created
application/json
created
{
"id": "bot_8122f0cb",
"server_id": "srv_1eea3e72",
"name": "Ops Bot",
"description": "",
"avatar_url": null,
"token": "9d1d2ff8f4acb720f84d5f7f5c6360e6c0a3db8de27d06c9d273b0f9306f7c22",
"user_id": "usr_bot_2bcbf5ee",
"default_channel_id": "ch_6fb77a2e",
"delivery_url": "",
"delivery_secret": "33861fe7f0f7bb16c31e2212864f56722dc65c6f4e7f3b84fdc0cc42d581d4f1",
"delivery_events": "",
"delivery_enabled": false,
"consecutive_failures": 0,
"disabled_reason": null,
"created_by": "usr_38f40aba",
"created_at": "2026-04-18 20:11:10",
"url": "https://uproar.chat/api/bots/bot_8122f0cb/9d1d2ff8f4acb720f84d5f7f5c6360e6c0a3db8de27d06c9d273b0f9306f7c22"
}400 Validation failure
application/json
nameRequired
{
"error": "name is required"
}nameTooLong
{
"error": "name too long (max 32 characters)"
}botLimit
{
"error": "server bot limit reached (max 25)"
}invalidChannel
{
"error": "invalid channel"
}
POST
/api/servers/{id}/bots/{botId}/regenerate
Rotate bot execute token. Old execute URL immediately stops working.
Parameters
| Name | In | Required | Type | Description |
|---|
id | path | required | string | Server ID. |
botId | path | required | string | Bot ID. |
Responses
200 Token regenerated
application/json
default
{
"token": "7e9aa9bbec06890f65c6581d2e2c6b13a74f5e0e414db469ac719f76a4f4f286",
"url": "https://uproar.chat/api/bots/bot_8122f0cb/7e9aa9bbec06890f65c6581d2e2c6b13a74f5e0e414db469ac719f76a4f4f286"
}
POST
/api/servers/{id}/bots/{botId}/test
Sends a signed test_ping event to delivery_url.
Notes:
- Returns HTTP 200 with
success: true|false for connection/result outcomes.
test_ping does not depend on delivery_events subscription list.
Parameters
| Name | In | Required | Type | Description |
|---|
id | path | required | string | Server ID. |
botId | path | required | string | Bot ID. |
Responses
200 Test attempted
application/json
success
{
"success": true,
"status_code": 200
}upstreamFailure
{
"success": false,
"status_code": 500
}connectionFailure
{
"success": false,
"error": "connection failed"
}invalidDeliveryURL
{
"success": false,
"error": "invalid delivery URL"
}privateInternalURL
{
"success": false,
"error": "delivery URL points to a private/internal address"
}dnsFailure
{
"success": false,
"error": "DNS resolution failed for delivery URL"
}400 Missing delivery URL
application/json
noDeliveryURL
{
"error": "no delivery URL configured"
}404 Bot not found
application/json
botNotFound
{
"error": "bot not found"
}
POST
/api/bots/{id}/{token}
Execute one bot action.
Supported actions:
send (default when action omitted)
edit
delete
react
unreact
pin
unpin
When action is omitted, it defaults to send.
Action-specific requirements:
send: channel_id can target any channel in the bot's server (not just the default). When omitted, falls back to default_channel_id. Requires at least one of content or embeds. Optional display_name and avatar_url override the bot's identity for this message (useful for bridge bots proxying other users).
edit: requires message_id; requires at least one of content or embeds; can only edit the bot's own messages.
delete: requires message_id. A bot with manage_messages permission can delete other users' messages.
react: requires message_id and emoji. Duplicate reactions are idempotent (always returns {"status":"ok"}).
unreact: requires message_id and emoji. No reaction permission check, but requireChannelWritable still applies (fails on archived channels).
pin/unpin: requires message_id.
Embed validation:
- up to 10 embeds
- total text chars across embeds <= 6000
color must be integer 0..16777215
thumbnail.url and image.url must use https:// when non-empty
- unknown embed keys pass through to storage as-is
- embeds are silently dropped if the bot lacks the embed_links permission
Additional send behavior:
reply_to must reference a valid message ID in the target channel. Returns 400 invalid reply_to message if not found or in a different channel.
@username mentions in content are resolved against server members with access to the target channel. Unresolvable mentions are left as plain text.
@everyone and @here in content set mentions_everyone on the message only if the bot has mention_everyone permission. Without the permission, the text is sent but no notification is triggered.
- All actions fail with 403 if the target channel is archived.
Parameters
| Name | In | Required | Type | Description |
|---|
id | path | required | string | Bot ID for execute endpoint. |
token | path | required | string | Bot execute token. |
Request Body
application/json
sendText
{
"action": "send",
"channel_id": "ch_6fb77a2e",
"content": "Hello from my bot."
}sendProxy
{
"action": "send",
"channel_id": "ch_6fb77a2e",
"content": "Hello from the other side!",
"display_name": "BridgedUser",
"avatar_url": "https://cdn.discordapp.com/avatars/123/abc.png"
}sendReply
{
"action": "send",
"channel_id": "ch_6fb77a2e",
"content": "Replying to your message.",
"reply_to": "msg_aabb1122"
}sendEmbed
{
"action": "send",
"channel_id": "ch_6fb77a2e",
"embeds": [
{
"title": "Crypto Prices",
"description": "Live prices via CoinGecko",
"color": 5242879,
"fields": [
{
"name": "BTC",
"value": "$68432.12",
"inline": true
},
{
"name": "ETH",
"value": "$3442.51",
"inline": true
},
{
"name": "SOL",
"value": "$171.24",
"inline": true
}
],
"footer": {
"text": "Type !price or $price to refresh"
}
}
]
}edit
{
"action": "edit",
"message_id": "msg_92bb6c1f",
"content": "Updated text"
}delete
{
"action": "delete",
"message_id": "msg_92bb6c1f"
}react
{
"action": "react",
"message_id": "msg_92bb6c1f",
"emoji": "🔥"
}unreact
{
"action": "unreact",
"message_id": "msg_92bb6c1f",
"emoji": "🔥"
}pin
{
"action": "pin",
"message_id": "msg_92bb6c1f"
}unpin
{
"action": "unpin",
"message_id": "msg_92bb6c1f"
}
Responses
200 Success (non-create actions)
application/json
edit
{
"id": "msg_92bb6c1f",
"channel_id": "ch_6fb77a2e",
"user_id": "usr_bot_2bcbf5ee",
"content": "Updated text",
"is_pinned": false,
"suppress_embeds": false,
"mentions_everyone": false,
"created_at": "2026-04-18 20:16:31",
"edited_at": "2026-04-18 20:18:00",
"username": "bot.2bcbf5ee",
"display_name": "Ops Bot",
"avatar_url": null,
"is_bot": true,
"reactions": []
}delete
{
"status": "deleted"
}react
{
"status": "ok"
}201 Created (`send` action)
application/json
send
{
"id": "msg_92bb6c1f",
"channel_id": "ch_6fb77a2e",
"user_id": "usr_bot_2bcbf5ee",
"content": "Hello from my bot.",
"is_pinned": false,
"suppress_embeds": false,
"mentions_everyone": false,
"created_at": "2026-04-18 20:16:31",
"edited_at": null,
"username": "bot.2bcbf5ee",
"display_name": "Ops Bot",
"avatar_url": null,
"is_bot": true,
"reactions": []
}400 Validation failure
application/json
invalidAction
{
"error": "invalid action; valid: send, edit, delete, react, unreact, pin, unpin"
}noContent
{
"error": "content or embeds required"
}tooLong
{
"error": "message too long (max 2000 characters)"
}noChannel
{
"error": "channel_id is required (no default channel set)"
}invalidChannel
{
"error": "invalid channel"
}invalidEmbeds
{
"error": "invalid embeds format"
}tooManyEmbeds
{
"error": "max 10 embeds per message"
}embedCharLimit
{
"error": "embeds exceed 6000 character limit"
}badEmbedColor
{
"error": "color must be an integer 0-16777215"
}badThumbnailUrl
{
"error": "thumbnail URL must use https://"
}badImageUrl
{
"error": "image URL must use https://"
}missingMessageId
{
"error": "message_id is required"
}missingEmoji
{
"error": "message_id and emoji are required"
}invalidReplyTo
{
"error": "invalid reply_to message"
}403 Permission denied, bot timed out, or channel archived
application/json
timedOut
{
"error": "bot is timed out",
"retry_after": 123
}noSendPerm
{
"error": "bot lacks permission to send in this channel"
}archivedChannel
{
"error": "cannot send messages in an archived channel"
}noDeletePerm
{
"error": "bot lacks permission to delete this message"
}noReactPerm
{
"error": "bot lacks reaction permission"
}noPinPerm
{
"error": "bot lacks pin permission"
}editOwnOnly
{
"error": "can only edit the bot's own messages"
}404 Bot or message not found
application/json
botNotFound
{
"error": "bot not found"
}messageNotFound
{
"error": "message not found"
}429 Rate limit or slowmode
application/json
botRateLimit
{
"error": "rate limit exceeded",
"retry_after": 60
}channelSlowmode
{
"error": "slowmode active",
"retry_after": 4
}