Chat SDK
Chat APIs Explained: Architecture, Protocols, and How to Pick One
Every chat experience you’ve ever used – WhatsApp, Slack, Discord, or that in-app support bubble on your favorite shopping site – looks different, yet that’s the same core chat backend. A system exposed through API that accepts connections from clients, routes messages between users, maintains enough state to make conversations coherent, and keeps everything reliable even when networks flake out or users go offline.
The annoying part is that “Chat API” gets stretched to cover almost anything. Sometimes it’s literally one REST endpoint that spins up a chatroom and does nothing else. Other times it’s a whole SDK bundled with React components, AI bots, a moderation pipeline, the works. Both get called the same name, and if you’re trying to compare options, that’s exactly the kind of ambiguity that wastes an afternoon.
So this article starts from the bottom and works up: what is a Chat API is and what it does, the transports underneath it – WebSocket, MQTT, XMPP, and a couple of others worth knowing about – what’s running on the server to hold all this together, and a way to pick one that won’t have you quietly regretting the choice eighteen months in.
In this article
- What a Chat API actually does
- Chat API vs SDK vs UI Kit vs Widget
- The protocols beneath a Chat API
- A minimal Chat API call, end-to-end
- The architecture beneath a Chat API
- How to pick: the 7-criterion framework
- Where Ethora fits
What a Chat API Is and What it Does
A Chat API is a ready-made tool that lets developers easily add real-time messaging, live chat, or AI-powered conversations to their app or website – without having to build all the complicated backend infrastructure from scratch.
Strip away the branding, and every Chat API is doing six things. Everything else – typing indicators, reactions, threads, moderation, voice and video, file sharing, push – is built on top of these six, and once you see them, you start noticing how thin the “everything else” layer actually is.
The first one is auth. It determines who is making a request and what they’re allowed to do. Without it, anyone can impersonate anyone else.
Then connect – opening a persistent transport, almost always a WebSocket, sometimes MQTT or a gRPC stream, that just stays open. The point is that the server can push data to the client whenever it wants, rather than the client constantly asking, “Anything new yet?”
Send – a message goes out with addressing attached – which channel, who it’s for, whatever metadata your app cares about. Receive is the mirror image, the server pushing that delivered message down an open connection to whoever’s listening on the other end.
Persist – someone has to write the message, the history, the attachments, the receipts somewhere that survives a restart – otherwise a user who steps away for an hour comes back to nothing. And notify covers the case where nobody’s listening at all: the recipient is offline, so a webhook fires and your app decides what to do about it – push notification, email, or just letting it sit in the queue until they show up.
Once you see these six primitives, most chat features stop looking special. A read receipt is just a message with a different type: sent, persisted, and delivered like any other. A typing indicator follows the same path but isn’t persisted. Many features in a chat SDK are simply these same primitives combined in different ways.
Chat API vs Chat SDK vs UI Kit vs Widget
These four terms get thrown around interchangeably in vendor marketing, but there’s a huge gap between them – in both effort and control.
Chat API – the protocol layer. Raw REST endpoints plus a real-time channel. Unopinionated. POST /channels/{id}/messages is a Chat API call. You write everything: the client, the reconnection logic, the UI, all of it. Maximum control, maximum work.
Chat SDK – a library wrapping the API. Platform-specific (JS, Swift, Kotlin, Dart, Python). Handles reconnects, retries, offline queueing, and gives you typed objects instead of raw JSON. You still build every screen, but you’re not reimplementing the network layer.
Chat UI Kit – framework-native components. React, React Native, Flutter, iOS, Android components for message lists, bubbles, attachments, and input boxes. You assemble screens from these, building design that matches your brand. The SDK underneath handles state; you handle layout and branding.
Chat Widget – drop-in, configured, done. A script tag for web or a screen for mobile. Full chat experience with minimal configuration. Least customization, fastest to ship – sometimes minutes.
Most vendors worth your time ship all four and let you mix and match. The real question isn’t “which layer is best” – there’s no best, just different amounts of work you’re signing up for. It’s “what’s the lowest layer that solves my actual problem without making me maintain plumbing I don’t care about.” A marketplace app will probably want the UI Kit for the main chat screen, because why build a message bubble component from scratch, but drop down to the raw API for that “make an offer” message type that no prebuilt component was ever going to support.
The Protocols Beneath a Chat API
This is the layer most explainers skip entirely, and it’s the difference between a chat feature that feels instant and one that feels like refreshing your email.
REST/HTTP
Everything that isn’t the live message itself runs over plain old REST: create a channel, pull message history, upload an attachment, update a profile. Nothing surprising here – stateless, cacheable, scales the boring way horizontally. The one thing worth remembering is that no serious chat system in 2026 delivers the actual live messages over REST. If you see that, something’s off.
WebSocket
For the real-time leg, WebSocket (RFC 6455) won, and it won years ago. One persistent connection, full-duplex, the server can shove a message at the client whenever it wants without being asked. Once the connection’s up, the per-message overhead is tiny. Browser support has been universal for so long that “does WebSocket work here” stopped being a question worth asking. Pretty much every chat SDK you’ll evaluate uses it as the primary transport, and there’s not much of a debate left about whether that’s right.
MQTT
MQTT came from IoT – it was built for sensors that couldn’t afford to waste battery or bandwidth on chatty protocols. Turns out a phone on a spotty 4G connection has basically the same problem as a sensor in a field, so MQTT made the jump into chat. Facebook Messenger’s mobile clients ran on it for a long time, and you’ll still find it anywhere a team cares a lot about battery life or started out building IoT infrastructure and bolted chat on afterward.
XMPP
XMPP – the name stands for Extensible Messaging and Presence Protocol – has been around since the early 2000s and quietly runs a lot of enterprise messaging you’ve never thought about. WhatsApp’s original wire protocol started as XMPP too, though by the time WhatsApp was running at the scale it does now, the protocol had been modified into something the original spec authors probably wouldn’t recognize. You won’t pick XMPP for a new product in 2026, but its DNA is in a surprising number of systems, particularly anywhere presence – who’s online, who’s typing – matters as much as the messages themselves.
Server-Sent Events (SSE)
SSE is the protocol you reach for when you only need the server talking to the client, never the other way. It’s just HTTP, which makes it almost embarrassingly simple to set up compared to WebSocket – but the moment your client needs to send anything back, you’re bolting on a second mechanism, which mostly defeats the point. You’ll see this more in “here’s a live feed of notifications” features than in actual two-way chat.
gRPC bidirectional streaming
gRPC over HTTP/2 with protobuf gets you typed, efficient, bidirectional streams – genuinely nice if you’re writing backend services that talk to each other. The catch is the browser. gRPC-Web exists and works, but it’s not the smooth first-class experience gRPC gets everywhere else, which is basically why you see it powering the guts of a system rather than the chat UI itself.
GraphQL subscriptions
If your whole API is already GraphQL, subscriptions let real-time chat ride on top of a WebSocket using the schema and resolvers you already have – one mental model for queries, mutations, and live updates. The trade-off is overhead: every message goes through the GraphQL layer instead of being a bare WebSocket frame. For most chat volumes, that overhead is invisible. At very high message rates, it starts to show up on a profiler, but “very high” here means a lot more than typical chat traffic.
WebTransport and WebRTC DataChannel
WebTransport is the new kid – built on HTTP/3, lower latency than WebSocket, and it handles switching networks (wifi to cellular) without dropping the connection, which WebSocket has always been clumsy about. Browser support is getting there but isn’t universal yet, so it’s a “watch this space” rather than a “use this now.” WebRTC DataChannel is a different animal entirely – it’s peer-to-peer, the server gets cut out of the data path completely. Great for specific low-latency scenarios, but you lose the server-side persistence and fan-out that most chat products actually depend on, so it’s rarely the answer for general chat.
| Protocol | Direction | Common in chat? | Best for |
|---|---|---|---|
| REST/HTTP | Request/response | Yes – control plane | History, uploads, user mgmt |
| WebSocket | Bidirectional | Yes – the default | Live message delivery |
| MQTT | Pub/sub | Mobile-heavy use cases | Battery-constrained clients |
| XMPP | Bidirectional | Legacy/enterprise | Federation, presence-heavy |
| SSE | One-way (server→client) | Notifications more than chat | Simple server push, no reply needed |
| gRPC streaming | Bidirectional | Backend/mobile, not web | Service-to-service, native apps |
| GraphQL subscriptions | Bidirectional (over WS) | If already on GraphQL | Unified query+subscribe API |
| WebTransport | Bidirectional | Emerging | Future low-latency default |
What you’ll actually use
Realistically: REST for the control plane, WebSocket for live messages, APNs/FCM for push when someone’s offline. That’s it – that’s the stack behind almost every chat product you’ve used. The other protocols on this list each solve a real problem, just not usually yours: MQTT if you’re fighting for every byte on mobile, XMPP if you inherited a federated system, GraphQL subscriptions if your whole stack is already GraphQL.
A Minimal Chat API Call, End to End
Here’s the loop every Chat API implements in some form. The exact schema differs by vendor, but the shape is the same everywhere. This is illustrative pseudocode – the structure is representative, not a specific vendor’s exact API.
Step 1 – Auth
POST /auth
{ "userId": "u_123", "secret": "..." }
// → { "jwt": "eyJhbGciOi..." }Exchange credentials for a short-lived token. Everything after this point is scoped to whatever permissions that token carries.
Step 2 – Connect
const ws = new WebSocket(
'wss://api.example.com/v1/connect?token=eyJhbGciOi...'
);Open the persistent transport. From here, the server can push to this client at any time.
Step 3 – Send
ws.send(JSON.stringify({
type: 'message',
channel: 'c_42',
text: 'hello',
meta: {}
}));Submit a message with its addressing – which channel it belongs to – and any metadata your app cares about (reply-to ID, custom message type, attachments).
Step 4 – Receive
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
render(msg);
};The server pushes the message to the sender as confirmation, and to every other connected participant in the channel.
Step 5 — Persist & fetch
GET /channels/c_42/messages?before=2025-12-01
// → [{ id: 'm_98', text: '...', sentAt: '...' }, ...]History lives behind a REST endpoint, not the WebSocket – this is the control-plane/data-plane split in practice. A client reconnecting after being offline calls this to catch up.
Step 6 — Receipts
ws.send(JSON.stringify({
type: 'receipt',
messageId: 'm_99',
state: 'read'
}));Same connection, same primitive (Send), different message type. This is what becomes the “blue tick” in the UI.
Step 7 — Webhook on offline
// Server-side, fired when recipient has no active connection
POST https://your-app.com/hooks/message
{ "recipientId": "u_456", "messageId": "m_99" }
// Your server decides: push via APNs/FCM, email, nothingThis is the Notify primitive. The Chat API doesn’t know or care how you reach an offline user – it just tells you that you should.
Every vendor’s API is some variation of this seven-step loop. Where they actually differ: how rich the metadata schema is (can you attach arbitrary structured data to a message, or only text?), the error model (what happens on rate limit, on invalid channel, on expired token), and what’s built on top – threads, reactions, custom message types for things like marketplace offers or appointment bookings.
The Architecture Beneath a Chat API
So what’s actually running on the other end of that WebSocket to make the seven-step loop hold up under real traffic? More than you’d guess from the API surface.
Start at the edge: something has to terminate TLS, check that the auth token, and hold your socket open for as long as you’re connected. That’s the edge gateway, and it usually exists in multiple regions – there’s no point making someone in Singapore round-trip to a server in Virginia for every message they send. NGINX or Envoy as reverse proxies get you part of the way; a lot of teams end up writing custom gateways in Go or Rust specifically for the connection-handling piece, because that’s where the interesting performance work happens.
Once a message lands at the edge, it has to get to wherever the recipient’s connection actually is – which might be a completely different server. That’s the job of the message bus. Kafka, Redis Streams, and NATS show up a lot here; some vendors have rolled their own. What this layer buys you is ordering and at-least-once delivery – the guarantee that if a server crashes mid-delivery, the message doesn’t just evaporate. It’ll show up eventually, possibly more than once, which is a much better failure mode than “gone forever.”
Then there’s persistence – which is really three different storage problems wearing one name. Message history goes in something like Postgres, Cassandra, ScyllaDB, or DynamoDB, depending on how much scale you’re dealing with and how you query it. Attachments – images, files, voice notes – go in S3 or GCS, because nobody’s storing binary blobs in their primary database if they can avoid it. And if users need to search across history, that’s usually a separate index in Elasticsearch or OpenSearch, because full-text search is a different problem from “give me the last 50 messages in this channel.”
Presence – the “who’s online right now” indicator – is the one piece here that genuinely doesn’t need to survive a restart. It’s almost always Redis with a TTL on each key. If the server goes down and comes back up, presence just rebuilds itself as everyone reconnects and re-announces. Nobody’s losing sleep over presence data durability, because durability isn’t the point.
For notification fan-out, picture a worker tier sitting behind a queue, watching for “this user is offline and just got a message” events and turning them into actual pushes – APNs for iOS, FCM for Android, web push, maybe falling back to email or SMS if nothing else lands. The queue matters because push providers have rate limits, and a sudden burst of messages – say, someone posts in a busy group chat – shouldn’t slam into those limits all at once.
Then there’s the moderation pipeline – hooks that fire before or after a message is sent, run it through an AI classifier, and route anything uncertain to a human queue. A few years ago this was the kind of thing you bolted on later if you had a toxicity problem. Now, under DSA and EU AI Act obligations, it’s closer to a load-bearing wall than an add-on for platforms that fall in scope.
Every decision the moderation pipeline makes – sent, blocked, flagged, delivered – gets written down somewhere for audit and analytics. Two different audiences read this log: compliance teams who need to produce it under DSA Article 24 if a regulator comes asking, and product teams who are just trying to understand engagement. Same data, very different reasons to care about it.
And then multi-region replication, which only becomes a real conversation once data residency requirements show up – EU-only, US-only, whatever your contracts or regulators demand. At that point, you’re running regional clusters with cross-region sync limited to whatever’s actually legal to move across borders. This is also where “self-hosted” stops being a checkbox feature and starts being the only honest answer – a vendor’s cloud regions are whatever they decided to build, and yours are wherever you decide to put servers.
How to Pick a Chat API: The 7-Criterion Framework
Once you have decided to add a chat feature, you need to choose it. Here is what to pay attention to.
Transport and latency
WebSocket should be your default assumption at this point – if a vendor isn’t using it for live messages, ask why. And when you’re looking at latency numbers, ask for the regional p95, not the average. Averages are where slow connections go to hide.
Feature coverage
1:1, group, broadcast, threads, reactions, receipts, presence, attachments, voice/video. Go through this list against what your product actually needs – not what looks impressive on the vendor’s comparison page, which is a different exercise entirely.
SDKs and UI Kits
Whatever platforms you ship on, check that the SDKs actually have feature parity across them. React Native, iOS, Android, and Web are the combination most teams end up needing, and a gap between two of those platforms doesn’t stay small – it becomes the thing your mobile team is quietly working around six months from now.
Moderation and AI
Is it built in, or do you wire it up yourself via webhook? And the question that’s started to matter a lot more recently: can you bring your own model – BYO LLM – or are you stuck with whatever the vendor decided to build, at whatever price they decide to charge for it?
Compliance
HIPAA with an actual signed BAA, GDPR, SOC 2 – and the question underneath all of those: if your security team’s bar is high enough that no vendor’s attestation will satisfy it, is self-hosting even on the table?
Pricing model
Per-MAU, per-message, flat tier, one-time license – model what each one costs at your projected scale a year out, not at today’s numbers. The pricing model that looks cheapest right now is very often the one that hurts most once you actually succeed.
Lock-in and portability
Is the protocol something proprietary to this vendor, or a standard like XMPP that other systems speak to? Can you actually get your message history out in a usable form if you need to? And if the relationship with this vendor ever has to end, can you self-host, or are you stuck?
Where Ethora Fits
Going back to the four layers from earlier – API, SDK, UI Kit, Widget – Ethora ships all of them. WebSocket transport with a REST control plane underneath, SDKs for React, React Native, iOS, Android, Node.js, and Python, React UI Kits if you want the component layer, and a five-minute Ethora Chat SDK widget if you just need to ship something today.
Compared to other providers, the differences that actually matter come down to three things. Self-hosting means you own the data outright and can make HIPAA, GDPR, or SOC 2 claims without going through a vendor’s BAA process – it’s your infrastructure, your attestation. Teams operating in regulated industries such as healthcare, government, and finance often choose our on-prem chat SDK to meet internal security and compliance requirements.
BYO-LLM through the AI Bots SDK means moderation and AI agents run on whatever model you pick – OpenAI, Anthropic, a local Llama Guard 3 deployment, whatever fits – instead of being locked to one vendor’s stack and whatever they decide to charge for it next year.
And the pricing is flat-tier, so going from 10,000 users to 500,000 doesn’t change the bill. On top of that, it’s modular – install the chat engine, add AI bots if and when you need them, add the RAG crawler later – so you’re not paying upfront for modules that sit unused.
So, whether you need a chat API for web applications, iOS apps, Android apps, React Native, Ethora’s robust infrastructure will fit almost any use case, enabling you to build a messaging solution in days or a few weeks, not months.
If you‘d like to explore more and learn how you can benefit from using Ethora, drop us a line.
More Articles
AI SDK
Aug 6, 2026
Ethora 26.08: AI Message Translation, Secure Attachments, and a Compliance Audit Trail
Ethora 26.08 ships real-time AI message translation, membership-gated secure attachments, immutable audit logs, and self-hosted monitoring and load-testing tools.
Chat SDK
Aug 3, 2026
Chat SDKs Compared: How to Pick One for Your Stack, Scale, and Compliance Needs
This chat SDK comparison covers nine vendors and the open-source option across the criteria that actually decide whether an SDK survives contact with a real codebase and a real compliance team.
Try Out Ethora in Action
Experience Ethora's messaging with a dedicated demo from our CEO or start building your App right now!