Strafe Developer Documentation
Build bots that live in spaces, and applications that let people sign in with Strafe. Both go through the same two doors: a REST API and a real-time WebSocket gateway. Everything on this site describes the instance you are reading it on - the addresses in the sidebar are this instance's own.
What you can build#
| You want to… | Use | Start with |
|---|---|---|
| Run a bot that reads and posts messages in spaces | A bot - an application's bot account, authenticated with a bot token | Bots |
| Let people log in to your site or app with their Strafe account | OAuth2 - the authorization code grant with the identify / email / spaces scopes | OAuth2 |
| Let a bot add people to a space from your own website | OAuth2 with the spaces.join scope, plus a bot with Create Invite | OAuth2 › spaces.join |
| Let anyone add your bot to their space with a link | An install link with the bot scope and a permissions value | Applications › Install links |
Quick start#
- Open Settings → Developers in the Strafe client and create an application. You get a client ID and a client secret (shown once).
- Add a bot to the application. You get a bot token (shown once). The bot's user ID is the same as the application's client ID.
- Add the bot to a space you manage with the Add to a space button, or share the link the URL generator builds.
- Talk to the API with
Authorization: Bot <token>, and connect to the gateway with the same header to receive messages as they happen.
# Who am I?
curl -H "Authorization: Bot $BOT_TOKEN" <API>/users/@me
# Say hello in a room
curl -X POST -H "Authorization: Bot $BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"plaintext":"Hello from my bot!"}' \
<API>/rooms/ROOM_ID/messagesReplace <API> with this instance's API base: https://your-instance.example/api.
This instance#
| URL | |
|---|---|
Web client (and the OAuth2 consent page at /oauth2/authorize) | https://your-instance.example |
| REST API base | https://your-instance.example/api |
| Gateway (WebSocket) | wss://your-instance.example/gateway/events |
| CDN (avatars, icons, attachments, emoji) | https://your-instance.example/cdn |
On a standard deployment the API is served under /api and the gateway under /gateway of the instance's domain. Paths in this documentation are relative to the API base: GET /users/@me means GET <API>/users/@me.
Authentication#
Every request carries one credential in the Authorization header. Nothing is read from cookies or query strings.
| Header | Who | Gets |
|---|---|---|
Authorization: Bot <bot token> | A bot | Everything the bot account may do - the same endpoints a person's client uses, gated by the bot's permissions in each space |
Authorization: Bearer <access token> | An application acting for a user who authorized it | Only the endpoints its scopes allow (see OAuth2 › Scopes); anything else is 403 insufficient_scope |
Authorization: Bearer <session token> | The Strafe client itself | A person's full account. Not for applications: never ask a user for their session token |
The gateway accepts the same Bot header on the WebSocket handshake.
Conventions#
- IDs are strings. Every id (
"2105141069376131072") is a 64-bit snowflake sent as a JSON string, because JavaScript numbers cannot hold it. Send ids back as strings too. - Timestamps are RFC 3339 / ISO 8601 in UTC:
"2026-09-30T03:44:45.361Z". - Permissions are integer bitmasks (see Permissions). They fit comfortably in a JavaScript number.
- JSON in, JSON out. Send
Content-Type: application/json. The one exception is the OAuth2 token endpoint, which also takes a form body as the standard requires, and file uploads, which aremultipart/form-data. - Errors are
{"error": "message"}with a matching HTTP status (400bad input,401bad or missing credentials,403not allowed,404not found,409conflict,429slow down). OAuth2 endpoints use the RFC 6749 error codes (invalid_grant,invalid_scope, …) and may add anerror_description. - Rate limits are per endpoint group and return
429with aRetry-Afterheader when exceeded. Slowmode in a room returns429withretry_afterseconds in the body. See REST › Rate limits. - End-to-end encryption. Private messages are end-to-end encrypted by default and space rooms can opt in. A bot cannot read or write in an encrypted room - messages there arrive with
ciphertextand noplaintext. See Bots › Encryption.
Vocabulary#
Strafe borrows Discord's interaction model with its own names. If you have written a Discord bot, this table is the translation:
| Strafe | Discord | Notes |
|---|---|---|
| Space | Server / guild | spaces in every path and payload |
| Room | Channel | Space text and voice rooms, and private messages, are all rooms |
| Section | Category | A room of type 5 that groups other rooms |
| PM / group PM | DM / group DM | Rooms of type 1 and 2; end-to-end encrypted by default |
| Member, role, invite, emoji, reaction | same |