Skip to content

Receiving updates ​

Everything that happens in the bot's chats arrives as an Update: a new message, an edit, a reaction, a button press. The bot's own messages are not reported.

Updates wait in a queue in the bot's volume until you confirm them. You get them in one of two ways: long polling (the default) or a webhook.

Update types ​

typeFieldWhen
messagemessageA new message: text, a file (download it with GET …/file), a poll.
editedmessageSomeone edited their message.
deleteddeletedA message was deleted for everyone.
reactionreactionA reaction was set; an empty emoji means it was removed.
pollmessageVotes in a poll changed or the poll was closed.
chatchatA new chat, a chat request, a group invitation; the group's title, members or disappearing-messages timer changed.
noticenoticeA system line in the chat, see notice codes.
expiredexpiredDisappearing messages were erased (an array of message ids).
buttonbuttonSomeone pressed a button with data. See buttons.

Commands are ordinary message updates whose text starts with /.

Long polling ​

http
GET /v1/updates?offset=<last id + 1>&timeout=30&limit=100
  • timeout — wait up to this many seconds (at most 60) if the queue is empty.
  • offset — confirms and removes every update with a smaller id. Pass the last id you processed plus one.
  • limit — at most this many updates (1–100, default 100).

The answer is a JSON array, possibly empty. If you crash before confirming, the same updates come again, so make your handling idempotent by id.

Webhook ​

Set WEBHOOK_URL (and WEBHOOK_SECRET) and the gateway POSTs every update to it, one JSON Update per request, strictly in order. GET /v1/updates then answers 409.

  • A 2xx answer means delivered.
  • Anything else, or no answer, is retried after 1 s, 2 s, 4 s … up to 5 minutes between attempts. The next update waits until this one is delivered.
  • The X-Mailbees-Signature header is sha256=<hex HMAC-SHA256 of the body with WEBHOOK_SECRET>. Check it before trusting the body.
python
import hashlib, hmac

def verify(body: bytes, header: str, secret: str) -> bool:
    want = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(want, header or "")
js
import { createHmac, timingSafeEqual } from 'node:crypto'

function verify(body, header, secret) {
  const want = Buffer.from('sha256=' + createHmac('sha256', secret).update(body).digest('hex'))
  const got = Buffer.from(header ?? '')
  return got.length === want.length && timingSafeEqual(got, want)
}
go
func verify(body []byte, header, secret string) bool {
	m := hmac.New(sha256.New, []byte(secret))
	m.Write(body)
	return hmac.Equal([]byte(header), []byte("sha256="+hex.EncodeToString(m.Sum(nil))))
}

Answer quickly and do slow work in the background: while you hold the request, the next updates wait.

Read receipts ​

Until the bot marks messages read, people see them as "delivered". Mark them with POST /v1/chats/{chat}/read. The countdown of disappearing messages starts for the bot from that moment too.