Rate Limits
Requests that are cheap to send and expensive to serve are throttled. Exceeding
a limit yields the rate_limited error; typing.set signals are silently dropped
instead, since they carry no response.
| Commands | Scope | Budget |
|---|---|---|
auth.phone, phone.set |
client address | 10 per minute |
auth.qr |
client address | 20 per minute |
invite.get |
client address | 30 per minute |
auth.token, auth.refresh |
client address | 60 per minute |
auth.code, phone.code |
phone number | 1 per 60 seconds; 5 SMS and 10 codes in the app per day |
auth.code, phone.code |
client address | 10 per hour |
auth.code, phone.code |
country of the number | set by the server |
auth.phone, phone.set |
verification | 5 wrong codes |
phonebook.update |
account | 10000 entries added per day |
user.search, conversation.search, message.search, phonebook.update |
connection | 20 per 30 seconds |
Message, voice play, read, delivery, draft, notification, reactions-seen, pin, block, privacy, moderation, contact, profile, presence, session, transport, push, activity, conversation, membership and invitation changes; qr.get, qr.accept; typing.set; phonebook.clear; files and transfers but file.get |
connection | 40 per 2 seconds |
Credential checks are limited per client address rather than per connection, so
reconnecting does not reset the budget. Every SMS costs money, and a stream of
codes to premium-rate numbers is a known way to spend someone else's: sending is
therefore limited by number, address and country at once, and a server may
refuse whole countries with not_supported. A rate_limited answer to a code
request carries retry_after. Behind a reverse proxy the address is
taken from X-Forwarded-For, but only when the proxy is configured as trusted —
otherwise every client would share the proxy's address, or be able to claim any
address it likes.