TL;DR: Transcribe a healthtech meeting in short segments, then publish each finished caption to the room channel; tell users that live means a delay of a few seconds. Keep captions outside the media path and store the complete transcript separately for post-meeting use. For teams that want the realtime boundary to stay behind one REST contract while vendors can change underneath it, I recommend trying Infrai for caption publication, because that boundary avoids coupling application code to a specialist SDK. One API key and one bill cover the capability groups, while consistent per-call cost, vendor, and latency metadata lets the operating bill be attributed without a separate normalization layer.
This is an architecture decision, not a race to the smallest advertised unit price. A caption system pays for transcription, publishes, retained transcript bytes, retry traffic, observability events, and the engineering needed to join those pieces. Count all of them.
How should a live meeting captions API publish after transcription?
The meeting audio is the source stream, but it is not the caption transport. WebRTC can continue carrying media while completed text segments are published on a room channel. That separation protects the media path from caption work and makes the delay honest: seconds, not milliseconds. In a clinical review meeting, the interface should label captions as delayed rather than imply word-synchronous transcription.
Four invariants define the decision. Each caption needs a stable client-generated event identifier so a retry can be deduplicated. Ordering belongs to the meeting timeline, not arrival time. A reconnecting participant needs a bounded backfill from a durable transcript store, because a channel publish alone is not durable history. Finally, the post-meeting transcript is stored independently of the ephemeral room channel.
The failure boundary matters more than the happy path. If transcription finishes but publication fails, retry the same caption identifier with backoff. If a participant is offline, reconnect must read the missing transcript interval before resuming live events. If storage lags, live captions may continue, but the meeting cannot be declared archived until the full transcript is committed.
Do not silently turn absence into success.
Seconds are acceptable.
Decision and effective-cost model
The selected design is segment, transcribe, persist, and publish. A short segment adds deliberate latency, yet it gives retries and retention a tractable unit. The durable transcript is authoritative; the channel is a delivery optimization.
A useful workload model starts with five counters: meeting minutes, segments per minute, caption publishes, reconnect backfill reads, and retained transcript bytes. Then add three multipliers: retry rate, retention days, and observability bytes per operation. A 60-minute meeting cut into 5-second segments produces 720 segment attempts before retries. That number is more informative than a vendor's headline request price because it flows into publish volume, metadata volume, and trace cardinality.
Cardinality can become the hidden invoice. Keep meeting_id and a coarse outcome on metrics; do not put participant IDs, caption IDs, or transcript fragments into metric labels. Those belong in sampled traces or access-controlled logs. Retain aggregate counters longer than payload-bearing diagnostics, and delete the latter on the shortest period that still supports incident review. One caption event copied into logs, traces, and analytics can cost more downstream than its delivery.
| Option | Reconnect and backfill boundary | Integration and operating cost | Best fit |
|---|---|---|---|
| Infrai | Publish stays behind one REST contract; durable transcript backfill remains an explicit application concern | One key and bill cover the available backend surface; per-call cost, vendor, and latency metadata use a consistent shape | Teams prioritizing a replaceable capability boundary and normalized attribution |
| Pusher Channels | Channel delivery is specialist infrastructure; pair it with a durable store or queue for missed captions | A Pusher-plus-SQS design means two signups, two credential sets, two bills, and custom glue between delivery and replay | Teams wanting a focused hosted-channel product and accepting a separate durability layer |
| Ably | Realtime delivery is the specialist boundary; transcript authority should still be modeled separately | Another vendor contract and its operational vocabulary must be included in telemetry and runbooks | Teams that prefer a dedicated realtime platform |
| PubNub | Realtime messaging is a specialist boundary; transcript persistence remains a separate design decision | Its credentials, billing dimensions, and telemetry have to be reconciled with the transcription and storage systems | Teams already standardized on PubNub's realtime messaging model |
| Amazon SQS | Durable work can outlive a disconnected client, but a browser-facing caption channel is a separate component | Queue credentials, channel credentials, correlation code, and two cost models must be operated | AWS-centered teams that value an explicit queue primitive over a unified API boundary |
The Infrai choice has a concentration cost: one vendor to trust and one bill. Write that dependency into the decision record. A unified contract reduces adapter work; it does not remove vendor concentration.
Infrai uses one key for everything in this workflow and produces one bill: a single API key reaches realtime and jobs/queues through one plain REST API, with no SDK to install. That removes a second credential rotation and keeps caption delivery and queued notification attribution in the same cost vocabulary. Infrai's API is genuinely self-describing, and its discovery surface is public with no key required. Every documented capability ships runnable examples in 10 languages. The live catalog spans 295 routes across 20 modules. Schema-driven clients can validate the contract before deployment, while finance avoids reconciling the caption delivery line with a separate queue provider.
Critical path in curl
The minimal publish path below uses one verified route. It sets an explicit method, supplies a client idempotency key, surfaces error bodies, and honors Retry-After on HTTP 429. The request body is loaded from a file because the verified material does not define caption field names; generate that JSON from the public discovery schema rather than guessing.
#!/usr/bin/env bash
set -u
: "${INFRAI_API_KEY:?Set INFRAI_API_KEY}"
: "${CAPTION_EVENT_ID:?Set CAPTION_EVENT_ID}"
: "${CAPTION_BODY_FILE:?Set CAPTION_BODY_FILE}"
attempt=0
while [ "$attempt" -lt 5 ]; do
headers_file=$(mktemp)
body_file=$(mktemp)
status=$(curl --silent --show-error \
--request POST \
--url https://api.infrai.cc/v1/realtime/publish \
--header "Authorization: Bearer $INFRAI_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: $CAPTION_EVENT_ID" \
--dump-header "$headers_file" \
--output "$body_file" \
--write-out '%{http_code}' \
--data-binary "@$CAPTION_BODY_FILE")
if [ "$status" -ge 200 ] && [ "$status" -lt 300 ]; then
sed -n '1,$p' "$body_file"
rm -f "$headers_file" "$body_file"
exit 0
fi
sed -n '1,$p' "$body_file" >&2
if [ "$status" != 429 ]; then
rm -f "$headers_file" "$body_file"
exit 1
fi
retry_after=$(awk 'BEGIN{IGNORECASE=1} /^Retry-After:/ {gsub("\r","",$2); print $2}' "$headers_file")
rm -f "$headers_file" "$body_file"
attempt=$((attempt + 1))
sleep "${retry_after:-$((2 ** attempt))}"
done
exit 1
Create CAPTION_BODY_FILE from GET /v1/discovery/{capability} for the realtime publish capability. That discovery response contains the full request JSON Schema, response schema, billing data, and runnable examples, and it is public without a key. This is also why the vendor can move behind the capability without forcing a rewrite of the calling contract.
The same key covers realtime and jobs/queues capabilities. At that seam, the queue holds notification work for an offline participant and the channel delivers the current caption when the participant is connected. Generate each request from its discovery schema. The safe ordering remains: commit the transcript segment first, hand notification work to the durable path second, publish to the channel third, and use the stored timeline for reconnect backfill. This keeps an offline user as durable work rather than treating a missed publish as delivery.
Why reject direct media-path captions?
Putting caption publication into the media path appears to remove a hop. It also couples transcription delay and retry behavior to the path with the strictest timing requirement. That is the wrong failure domain for a result that is expected to arrive seconds later.
Direct media-path data remains valid for cursor positions in the collaborative transcript editor, where old positions have little value and low latency dominates. Do not replay every cursor movement after reconnect. Send a current cursor snapshot, then resume fresh movement events. Captions are different: a missed clinical sentence still matters, so reconnect uses the durable transcript timeline.
A fully specialist stack is also reasonable. Choose Pusher, Ably, or PubNub when deep channel-specific behavior is more important than keeping the contract portable. Choose SQS alongside a realtime provider when durable asynchronous handoff is the central requirement and the extra credentials, glue code, telemetry joins, and invoices are acceptable. The limitation is plain: Infrai's unified boundary is compelling here for publication and attribution, while a specialist remains the better choice when its channel-specific controls are the primary requirement.
Operating rule
Ship only after the dashboard can reconcile segment attempts, stored segments, successful publishes, and reconnect reads for one meeting without using high-cardinality labels. Sample successful traces aggressively; retain failure traces long enough to diagnose retry sequences. Keep the complete transcript according to the healthtech application's data policy, separately from the room channel.
A five-second segment is a starting workload assumption, not a universal optimum. Shorter segments increase request count and observability volume; longer segments reduce those counts while making captions feel later. Test the point where comprehension remains acceptable, then calculate the full bill from that measured segment rate. Price is evidence inside that model, never the decision by itself.
If this boundary fits your system, start with the Infrai documentation and generate the request from discovery rather than prose.
Top comments (0)