Build on Sunflare
Writing Bots
A Sunflare bot is a real user account: same permissions, same channels and DMs, same roles, authenticated by a token instead of a password. There's no separate bot API surface to learn: a bot calls the exact same REST routes the app itself does.
There's no realtime gateway/websocket. A bot finds out about new messages by polling. The official SDK below does this for you (every 2s for watched channels, every 30s for the server/channel list).
Create a bot
From a server you manage: Server Settings → Bots → Create Bot. To create one that isn't tied to a specific server yet (useful if you're going to distribute it to other servers), use User Settings → Developer Portal → Create Bot instead.
Either way you'll get a token back exactly once. Copy it immediately, there's no way to view it again later (only regenerate, which invalidates the old one):
<botId>.<secret>
The Developer Portal is also where you regenerate a token or delete a bot account entirely (cascades: removes it from every server it's in).
Inviting a bot to a server
Every bot has an invite link:
https://sunflare.me/oauth2/authorize?client_id=<botId>
Opening it while logged in shows a consent screen listing servers you manage, and adds the bot to whichever one you pick. A server owner/manager can also skip this and add a bot directly from Server Settings → Bots if they already have its ID.
Authenticating requests
Every request needs an Authorization header in this exact form. Note the literal word Bot, not Bearer:
Authorization: Bot <botId>.<secret>
From there, a bot can call any normal authenticated route. There's no curated bot-only subset. In practice you'll mostly want:
| Route | What it does |
|---|---|
GET /profile | Confirm the token works and see the bot's own identity |
GET /api/servers | Servers this bot belongs to |
GET /api/servers/:id/channels | A server's channel list |
GET /api/channels/:id/messages | Recent messages in a channel |
POST /api/channels/:id/messages | Send a message: { text } |
PATCH /api/channels/:id/messages/:msgId | Edit a message the bot sent |
DELETE /api/channels/:id/messages/:msgId | Delete a message (needs Manage Messages if not the bot's own) |
GET / POST /api/dms and /api/dms/:id/messages | Direct messages, same shape as channels |
A bot's permissions come from whatever roles it holds in a server. Assign it a role the same way you would a person, under Server Settings → Roles. A bot can never be a server's owner.
Rate limits
Bots share the same general API limit as everyone else: 1200 requests/minute per IP. There's no separate, higher bot allowance. Plan polling intervals accordingly if you're running several bots from one machine/IP.
Quick start with the official SDK
bots/sunflare-bot.js in the repo wraps the polling and message routes into an event emitter:
const SunflareBot = require('./sunflare-bot');
const bot = new SunflareBot(process.env.SUNFLARE_BOT_TOKEN, {
baseUrl: 'https://sunflare.me'
});
bot.on('ready', () => console.log('Bot is ready'));
bot.on('message', async (msg) => {
if (msg.text === '!ping') {
await bot.sendMessage(msg.channelId, 'Pong!');
}
});
bot.login();
Methods available on a SunflareBot instance: login(), destroy(), getServers(), getChannels(serverId), getVoicePresence(serverId), getDms(), getMessages(channelId), getDmMessages(dmId), sendMessage(channelId, text), sendDmMessage(dmId, text), editMessage/deleteMessage, editDmMessage/deleteDmMessage, and watchChannel/watchDm (starts the 2s poll that emits 'message' for that conversation) with matching unwatch* calls.
A minimal runnable example lives at bots/example-bot.js; a more advanced sample doing voice/audio playback via WebRTC is under bots/music-bot/ (see its own README; there's no built-in voice SDK, it hand-rolls the WebRTC side with werift/ffmpeg/yt-dlp).
Building without the SDK
The SDK is a thin convenience wrapper. Nothing stops you calling the REST routes directly from any language:
curl -X POST https://sunflare.me/api/channels/CHANNEL_ID/messages \
-H "Authorization: Bot YOUR_BOT_ID.YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{"text":"Hello from curl"}'
Good to know
- A leaked token is exactly as dangerous as a leaked password. Regenerate immediately from the Developer Portal if one gets exposed.
- A banned bot account is rejected at the auth layer (
403) before any route runs. - There's no message-content webhook/push. If you need near-real-time behavior, watch the specific channels/DMs you care about rather than polling everything.
Docs