Great question — this design pattern (WebSocket for server → client, HTTP POST for client → server) is actually very common in real-time applications like Discord, Slack, etc., and it boils down to security, reliability, and simplicity on the server side.
Here’s a breakdown of why Discord uses HTTP POST for sending messages, but WebSocket for receiving them:
🔁 WebSocket (Server → Client): Real-time Push
Discord uses WebSockets to push events to clients (e.g., new messages, typing notifications, presence updates) because:
- Low latency, bidirectional, persistent connection
- Efficient for pushing lots of updates to thousands or millions of clients
- Maintains client session state, so the server knows what the client is subscribed to
📤 HTTP POST (Client → Server): Sending Messages
Users send messages via HTTP POST instead of WebSocket because:
1. Authentication and Rate Limiting Are Easier
- HTTP allows for fine-grained OAuth token verification, permissions checks, and IP-based rate limiting.
- Discord has strict global and per-user rate limits (e.g., 5 messages every 5 seconds in a channel) — these are easier to enforce with stateless HTTP requests.
2. Statelessness is a Feature
- HTTP requests are independent, which is great for robustness. If your WebSocket connection is dropped, you can still send messages.
- Easier to retry failed sends (e.g., if network drops) with a simple POST request.
3. Infrastructure Simplicity
- HTTP is backed by mature, scalable, battle-tested infrastructure like CDNs, load balancers, reverse proxies, and API gateways.
- WebSocket is more complex to scale on the server because it requires stateful long-lived connections.
4. Auditing and Logging
- HTTP APIs are easier to log, debug, and audit.
- REST endpoints can include payloads like message content, channel ID, nonce, attachments, etc., in a consistent, structured way.
5. Compatibility
- HTTP is universally supported, even on limited clients or proxies that may block WebSockets or kill idle connections.
🧠 Why Not Just Use WebSockets for Everything?
Technically, Discord could accept client messages over the WebSocket (the protocol allows for it), but:
- The server would need to track more client state.
- Malformed data would be harder to handle (less structured than an HTTP request).
- Rate limits and abuse prevention would be harder.
- Retry and reliability logic would have to be handled differently.
By splitting the flow:
- WebSocket = real-time notifications from server
- HTTP POST = user-generated actions to server
…it creates a cleaner, more robust architecture.
TL;DR
Discord uses:
- WebSockets for pushing data to clients → real-time, efficient, and persistent.
- HTTP POST for sending messages to the server → stateless, secure, easier to rate limit, audit, and scale.
It’s a deliberate design tradeoff for performance and maintainability.