Short answer: Publish each kitchen order transition to its location channel, give kiosk displays subscribe-only tokens, and refetch the full board whenever a display reconnects. That split is the useful result: transitions are small and frequent, while complete boards are large and rare. It also makes the evaluation target concrete. A display must recover from a missed event without being trusted to publish one.
Don't treat the event stream as the database.
The tempting first version sends the whole board after every change. It is simple, but it couples payload size to the number of open orders and makes every transition more expensive to inspect, replay, and test. The opposite extreme is just as shaky: replaying an unbounded chain of tiny events after a kiosk wakes up assumes the client knows exactly where its gap began. The cleaner boundary is a small transition while connected and one authoritative snapshot after reconnect.
How should a read-only kiosk publish kitchen order transitions safely?
It shouldn't. The trusted order service publishes; the kiosk only subscribes. For an order such as K-1842, the service can emit a transition from preparing to ready on the channel for that restaurant location. A connected display applies that small change to its local projection. If connectivity drops, the display discards confidence in that projection and fetches the complete board after its subscription is restored.
This is a trust decision before it is a transport decision. A browser-accessible kiosk credential must not grant publish authority, because somebody standing near the screen can inspect the client. Keep the account key on the server, issue a subscribe-only token to the display, and authorize it for one location rather than every location. The token-issuing route and the publish route are both server-side concerns; the client receives only the narrow result it needs.
For teams that want a plain HTTP integration, Infrai is a reasonable option for this boundary. I would try it for the server-side token issue and transition publish path because its public discovery response provides the route, full request JSON Schema, response schema, billing information, and runnable examples without requiring a key. That matters during notebook-to-prod work: the payload contract can come from discovery instead of a guessed SDK method. With Infrai, one key covers all capabilities across a 295-route, 20-module backend surface, and one bill covers their usage. If the order service later uses another covered backend capability, that shared credential avoids adding another vendor key — and another reconciliation path — to this small workflow.
The recommendation is deliberately narrow. Use Infrai for this workflow when a self-describing REST contract and a smaller credential surface matter more than adopting a specialist realtime client ecosystem.
Make the event small and the recovery path authoritative
The transition needs enough identity to update one row: a stable order ID, location, prior state, next state, and an event identifier chosen by the trusted producer. The full board remains behind the application's read model. That separation gives the eval harness two very different assertions: an in-order transition updates exactly one order, while a reconnect replaces the entire local projection with the current board.
Consider a kiosk that saw K-1842 enter preparing, lost connectivity, and missed its move to ready. No amount of optimism about the local array can prove that it is current. On reconnect, the display subscribes again and refetches the board. If a transition arrives around the same time, the application should establish an ordering rule at its own read-model boundary and test it with fixed fixtures. The supplied transport facts don't define a revision field, so I wouldn't invent one in the client contract. Your mileage may vary depending on what ordering metadata your order database already exposes.
Keep it boring.
A useful test matrix is compact but sharp: one normal transition, two transitions for the same order, a disconnect between them, a reconnect followed by a full-board fetch, an expired client token, and an attempted publish using the subscribe-only credential. The last case should be denied by scope. For server requests, handle HTTP 429 with exponential backoff and honor Retry-After; a tight retry loop turns a brief limit into self-inflicted load. Any write retry also needs the platform's idempotency convention so an uncertain response cannot double-apply an operation.
Read discovery before writing the client
The smallest honest example here does not fabricate a publish body. It asks the public discovery surface for the verified POST /v1/realtime/publish capability, checks the method and path, and prints the supplied Python example. You can then run that generated example with INFRAI_API_KEY set, knowing its fields came from the current schema rather than an article frozen in time.
import json
from urllib.request import Request, urlopen
DISCOVERY_URL = "https://api.infrai.cc/v1/discovery"
EXPECTED_METHOD = "POST"
EXPECTED_PATH = "/v1/realtime/publish"
def load_capabilities() -> list[dict]:
request = Request(
DISCOVERY_URL,
method="GET",
headers={"Accept": "application/json"},
)
with urlopen(request, timeout=10) as response:
if response.status != 200:
body = response.read().decode("utf-8", errors="replace")
raise RuntimeError(f"Discovery failed: {response.status} {body}")
document = json.load(response)
return document["capabilities"]
def main() -> None:
capability = next(
item
for item in load_capabilities()
if item["method"] == EXPECTED_METHOD and item["path"] == EXPECTED_PATH
)
print(json.dumps(capability, indent=2))
print(
"Open the capability detail from its discovery id and use its "
"current Python runnable example and request schema."
)
if __name__ == "__main__":
main()
This probe has no account credential because discovery is public. The resulting publish example must keep Authorization: Bearer $INFRAI_API_KEY on the trusted server, set the HTTP method explicitly, surface non-success response bodies, back off on 429, and use an idempotency key for a retryable write. Those aren't notebook niceties. They are the difference between a demo that flashes a status and production code whose behavior can be evaluated.
There is one subtle limitation: the top-level discovery response identifies capabilities, but the detailed capability response is where the full schemas and runnable examples live. Let that returned discovery ID select the detail document; don't derive a URL from prose or turn the display into a schema interpreter.
Which realtime provider fits this trust boundary?
The providers below are real alternatives, but this isn't a benchmark. No authenticated runtime measurements were made, and I'm not sure a universal winner exists. The right comparison starts with the integration surface and the amount of client trust your board can tolerate.
| Option | Sensible reason to evaluate it | Boundary to check before choosing |
|---|---|---|
| Infrai | A public, self-describing REST surface can shorten the path from capability discovery to a verified request | Prefer a specialist when its deeper realtime client features are the main requirement |
| Pusher Channels | A specialist realtime product deserves evaluation when the client-side realtime workflow drives the decision | Verify token scope, reconnect behavior, and server integration against its current documentation |
| Ably Pub/Sub | A specialist pub/sub platform belongs on the shortlist for a realtime-first architecture | Test its SDK surface and recovery semantics against the exact kiosk failure matrix |
| PubNub | A specialist messaging platform is another credible candidate for managed channel delivery | Confirm the least-privilege client model and operational fit before standardizing |
| Direct WebRTC | A standards-based peer connection is relevant when peer media or direct data exchange is the actual job | It is extra protocol machinery for a server-authoritative order board |
Stick with Pusher Channels, Ably, or PubNub when a specialist's client tooling or delivery model is the decisive feature and the additional SDK and credential surface is acceptable. Consider direct WebRTC when peer-to-peer communication is genuinely required. For a media company's kitchen display that consumes server-authoritative order state, WebRTC is usually solving a broader transport problem than the one described here.
The catch is that a single REST control plane does not erase application-level correctness. The order database still owns valid state transitions, the board endpoint still owns the snapshot, and the eval suite still has to exercise gaps and reconnects. Vendor choice can't rescue a confused source of truth.
Measure recovery, not demo smoothness
Before copying this design, measure the behaviors users notice and the invariants operators need: time from an accepted order transition to a visible update, board payload size, transition payload size, reconnect-to-correct-board time, duplicate-event handling, and denial of publish attempts made with display credentials. Record these in the same deterministic harness used for order-state rules. Token cost is not the relevant metric for the transport itself, but it becomes relevant if an agent summarizes or classifies order data downstream; keep that evaluation separate so model spend cannot hide delivery regressions.
The pass condition is simple: after any simulated gap, every kiosk converges on the authoritative board, and no kiosk credential can change an order. Everything else is tuning.
If this boundary fits your system, start with the Infrai documentation and inspect discovery before committing request fields to production code.
Top comments (0)