Receive customer messages as they arrive so your delivery bot can react to requests such as “teleport to me”. Use the HTTP endpoint for the initial read and after reconnecting; use WebSocket events for live updates.
Permissions
Create a key in Superpanel → Integrations → API with Read messages & receive live messages(messages:read). Add Send messages(messages:write) if the bot should reply. Existing keys do not gain these permissions automatically.
A key can only read its own shop's customer conversations. Support tickets, personal chats, other shops, wallet updates, and notifications are excluded. Reading through the API does not mark chats read or mark the owner online.
Read recent messages
GET https://popbob.gg/api/v1/messages?limit=100
Authorization: Bearer pb_live_your_key_hereWithout after, this returns the latest messages across the shop's customer conversations, oldest first.limit is an integer from 1 to 100 (default 100). Optionally add userId to select one customer's account ID, matching the order's accountUsername.
{
"messages": [
{
"chatId": "67f15e3c3d6d55ab781ac123",
"userId": "customer-account-id",
"message": {
"_id": "67f15e3c3d6d55ab781ac456",
"senderType": "user",
"senderId": "customer-account-id",
"content": "tp please",
"images": [],
"createdAt": "2026-10-21T12:00:00.000Z",
"replyToMessageId": null,
"eventType": null,
"orderId": null
}
}
],
"nextCursor": "opaque-cursor",
"hasMore": false
}Pass the returned nextCursor as afterto read newer messages. These pages are chronological; whenhasMore is true, fetch the next page immediately. An empty result still returns a usable cursor. Keep the sameuserId filter while advancing a cursor.
Receive live messages
wss://popbob.gg/api/ws/shop-api
Authorization: Bearer pb_live_your_key_hereConnect from your bot's backend with the Authorization header. Never put the key in the URL or browser code. This uses the standard WebSocket protocol. The server automatically subscribes the connection to the key's shop and sends:
{ "t": "event", "e": "ready", "d": { "shopId": "your-shop-id" } }Each new message arrives with the same chatId,userId, and message fields as an HTTP result row, wrapped in:
{ "t": "event", "e": "message:new", "d": { "chatId": "...", "userId": "...", "message": { "...": "..." } } }Events include customer messages, shop replies, and order events. To react only to customers, requiremessage.senderType === 'user'. Send replies with POST /api/v1/messages. The socket does not accept room subscriptions or chat mutations.
Reconnect and recover
- Connect the socket and start buffering message events.
- After
ready, fetch the HTTP endpoint using your last savednextCursor. Fetch all catch-up pages. - Process the HTTP rows, then buffered events. Deduplicate both sources by
message._idand save processed IDs durably before allowing the same delivery action to run again. - Save each HTTP page's cursor after successfully processing it. Live events do not advance the saved HTTP cursor. On a disconnect, reconnect with backoff and repeat this recovery.
For a brand-new bot, decide whether to process the initial recent messages or use them only to establish its starting cursor. Do not repeatedly fetch on a timer. The stream is live delivery; the HTTP endpoint recovers messages missed during a disconnect.
Bot example
This Node.js listener uses the ws package. It shows where to connect your game bot's delivery handler. Add the reconnect recovery and durable deduplication described above before performing deliveries.
import WebSocket from 'ws'
const key = process.env.POPBOB_API_KEY
const socket = new WebSocket('wss://popbob.gg/api/ws/shop-api', {
headers: { Authorization: `Bearer ${key}` },
})
socket.on('message', raw => {
const event = JSON.parse(raw.toString())
if (event.e !== 'message:new') return
const { userId, chatId, message } = event.d
if (message.senderType !== 'user') return
console.log({ userId, chatId, messageId: message._id, text: message.content })
// Pass this customer message to your game bot's handler.
})
socket.on('error', console.error)Use userId to match the customer to their order and its player details. A chat message identifies a Popbob account; it does not authenticate a Minecraft player name written in the text.
Limits and errors
HTTP reads and WebSocket handshakes share the key's 60 requests per minute limit. Pushed events do not consume that limit. A key can have up to 10 simultaneous API sockets. A limited handshake or HTTP request returns 429 withRetry-After.
Invalid or expired keys return 401; missing read permission or a banned shop or owner returns 403. Invalid cursors or query parameters return 400. Messaging suspension blocks sending; reads remain available. Active sockets recheck key validity and shop access before each delivered message and close with code 1008 when access is lost. Slow consumers may be closed with code1013; reconnect and recover through HTTP.