purrr for developers

purrr is a self-hosted, open chat platform. Everything the official client does goes through the same public REST API and WebSocket gateway documented here — there are no private endpoints.

new

Bots are live. Create one in the app under Settings → Bots, copy its token, and jump to the bot section.

Base URL

https://purrr.chat/api

Authentication

Log in to get a bearer token, then send it on every request:

curl -s https://purrr.chat/api/auth/login \
  -H 'content-type: application/json' \
  -d '{"login": "your-username", "password": "…"}'
# → {"access_token": "…", "refresh_token": "…", "user": {…}}

curl -s https://purrr.chat/api/users/@me \
  -H 'authorization: Bearer ACCESS_TOKEN'

Access tokens are short-lived; exchange the refresh token at POST /api/auth/refresh when they expire.

Core endpoints

EndpointWhat it does
get/api/guilds/@meServers you're in (incl. your role ids)
get/api/guilds/{id}Server detail: channels, roles
get/api/channels/{id}/messagesMessage history (snowflake-paginated)
post/api/channels/{id}/messagesSend a message
post/api/users/@me/channelsOpen a DM
get/api/users/{id}Public profile (incl. connections)
post/api/attachmentsUpload a file (multipart)

Ids are snowflakes, serialized as strings in JSON. Mentions use <@id> / <@&roleId>, custom emoji <:name:id>; a message starting with @silent pings nobody.

Bots

A bot is a real account your code drives — same REST API, same gateway, same permission system (give it roles like any member). Differences from a person:

Manage bots with your own (person) token:

EndpointWhat it does
post/api/botsCreate a bot ({"username": "…"}) — returns the token once
get/api/botsList your bots
post/api/bots/{id}/tokenRotate the token (old one dies instantly)
post/api/guilds/{id}/botsAdd a bot to a server you manage

A minimal echo bot is a WebSocket connection and one POST:

// identify on the gateway with the bot token:
→ {"op": "identify", "d": {"token": "Bot 1234.abc…"}}
← {"t": "MESSAGE_CREATE", "d": {"channel_id": "…", "content": "!ping", …}}

// then answer over REST:
POST /api/channels/{channel_id}/messages
Authorization: Bot 1234.abc…
{"content": "pong 🐾"}

Realtime gateway

Connect to wss://purrr.chat/gateway/ws, then authenticate with an identify frame (the token never rides in the URL):

→ {"op": "identify", "d": {"token": "ACCESS_TOKEN"}}
← {"op": "hello", "d": {"heartbeat_interval": 30000}}
→ {"op": "heartbeat"}                    // every interval
← {"t": "READY", "d": {…}}               // initial state
← {"t": "MESSAGE_CREATE", "d": {…}}      // events as they happen

Event payloads mirror the REST resources: MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, TYPING, PRESENCE_UPDATE, VOICE_STATE_UPDATE, and friends.

Rules of the road