Skip to Content
SignStream APIWebSocketsV3 Reference (beta)

WebSocket API V3 Configuration

Beta: V3 · Current: V2 — V3 is a closed beta. Endpoints, defaults, and limits may change; read limits and config_applied from session.ready at runtime rather than hard-coding. Use V2 for new production integrations until V3 reaches GA.

Overview

The V3 WebSocket API introduces an explicit session lifecycle with per-message correlation. Instead of a single fire-and-forget request per socket, a client opens a session, sends any number of text messages, and receives structured text.ack and result frames correlated to each message by a client-supplied id.

V3 supports two modes:

  • translate — one signed MP4 URL is returned per text message. Best for request/response integrations that want per-utterance media without managing a manifest.
  • stream — a signed HLS manifest URL (and optional CloudFront cookies) is returned on session.ready; subsequent text messages append signs to the ongoing stream.

Connection Details

Connection URL

WebSocket URL
wss://ai.api.production.signapsesolutions.com/ws/

Protocol version is auto-detected from the first message on the socket — sending {"type":"session.start", "version":"3.0", ...} selects V3. V1 and V2 remain supported on the same endpoint.

Authentication

Authentication for the closed beta is coordinated with Signapse — no headers are required on the WebSocket upgrade at this stage. General availability will require credentials presented through the API gateway; the exact mechanism will be documented here before GA.

Session Lifecycle

Client Server | | |-- WebSocket upgrade -------->| |<------ 101 Switching --------| | | |-- {"type":"session.start"} ->| |<-- {"type":"session.ready"} -| | | |-- {"type":"text","id":"1"} ->| |<--- {"type":"text.ack"} -----| |<---- {"type":"result"} ------| (MP4 URL, translate mode) | | |-- {"type":"session.end"} --->| |<-- {"type":"session.summary"}| |<------- close frame ---------|
  • session.start must be the first message. Sending anything else first returns session_not_started.
  • Sessions time out after 1 hour of inactivity.
  • Up to max_inflight (default 3) text messages may be pipelined before waiting for results.
  • result messages may arrive out of order relative to text submission order — always correlate by ref.

Message Schema

session.start (client → server)

session.start
{
"type": "session.start",
"version": "3.0",
"mode": "translate",
"config": {
  "output_format": "mp4",
  "digital_signer": "MAX",
  "language": "ASL",
  "resolution": "720p",
  "debug": false
}
}

Required fields: type, version, mode, config.digital_signer.

For MP4 output, set mode: "translate". output_format defaults to "mp4" in translate mode, so it can be omitted.

session.ready (server → client)

session.ready
{
"type": "session.ready",
"session_id": "sess-abc12345",
"config_applied": {
  "output_format": "MP4",
  "digital_signer": "MAX",
  "language": "ASL",
  "resolution": "720p"
},
"limits": {
  "max_text_length": 5000,
  "max_messages_per_minute": 60,
  "max_inflight": 3
}
}

config_applied echoes the config with defaults resolved — read it back to confirm what the server actually used. limits are per-account and may be tuned; do not hard-code them.

text (client → server)

text
{
"type": "text",
"id": "msg-1",
"data": "The next train to London Paddington departs from platform 4."
}
  • id — client-generated, must be unique within the session. Echoed back as ref on every downstream message. Used to correlate text.ack / result / error responses and for recovery via result.fetch. Reusing an id returns duplicate_id.
  • data — UTF-8 text, max size in bytes given by limits.max_text_length (default 5000).

text.ack (server → client)

Sent immediately after the server accepts a text message. Confirms the message entered the pipeline but does not yet mean rendering is complete.

text.ack
{
"type": "text.ack",
"ref": "msg-1",
"timestamp": "2026-07-16T12:00:00Z"
}

result (server → client) — translate mode

The MP4 is ready.

result
{
"type": "result",
"ref": "msg-1",
"url": "https://cdn.production.signapsesolutions.com/.../msg-1.mp4",
"url_expires_at": "2026-07-16T12:05:00Z",
"duration_seconds": 5.2,
"pipeline_ms": {
  "gloss": 120,
  "render": 800,
  "encode": 300,
  "total": 1220
}
}
  • url — presigned CDN URL. Fetch or hand to a player as-is.
  • url_expires_at — URL is valid for 5 minutes from issue. Download or hand off promptly; after expiry the file is deleted and result.fetch returns result_expired.
  • duration_seconds — video duration.
  • pipeline_ms — server-side timing breakdown across the three pipeline stages; useful for diagnostics.

session.end (client → server)

session.end
{ "type": "session.end" }

Requests a clean close. If the client drops without sending this, the session is still closed on socket close, but the client may miss the session.summary.

session.summary (server → client)

Final message before the socket closes.

session.summary
{
"type": "session.summary",
"session_id": "sess-abc12345",
"usage": {
  "messages_processed": 42,
  "errors_encountered": 1,
  "session_duration_sec": 1234.5,
  "total_video_duration_sec": 890.2,
  "bytes_transferred": 52428800
}
}

total_video_duration_sec is the billable video output for the session.

result.fetch (client → server) — recovery

If the socket drops between text.ack and result, reconnect (starting a new session) and, on the same or a new session, request the outstanding result by its original id:

result.fetch
{ "type": "result.fetch", "id": "msg-1" }

Only supported in translate mode. Returns the result if still cached (5-minute TTL); otherwise result_expired.

text.progress (server → client) — debug only

Emitted only when config.debug: true on session.start. One message per pipeline stage completion. Not for production use.

text.progress
{
"type": "text.progress",
"ref": "msg-1",
"stage": "gloss",
"status": "complete",
"duration_ms": 120
}

Configuration Reference

Fields on the session.start.config object:

config fields

NameTypeRequiredDescription
digital_signerstringrequired
The digital signer to render the output. Case-insensitive. Signapse will provide the list of signers available on your account (e.g. "MAX", "RAE").
languagestringoptional
British or American Sign Language.
Default: "BSL"
BSLASL
output_formatstringoptional
Output video format. For translate mode, leave as "mp4" or omit. For stream mode, use "hls".
Default: "mp4" (translate) / "hls" (stream)
mp4hls
resolutionstringoptional
Output resolution.
Default: "720p"
480p720p1080p
debugbooleanoptional
When true, emits text.progress messages for each pipeline stage. Not for production use.
Default: false
hlsobjectoptional
HLS output configuration. Only used when mode is "stream". Ignored in translate mode.

Codec, bitrate, and background are not client-selectable — they are fixed per signer/resolution on the server side.

Session Limits

Returned in session.ready.limits. Current defaults on the beta environment:

LimitDefaultBehaviour when exceeded
max_text_length5000 bytestext_too_long error, message rejected.
max_messages_per_minute60rate_limited error with retry_after_seconds. Retry after the hint.
max_inflight3backpressure error with retry_after_seconds: 2. Wait for outstanding results before sending more.
Session idle timeout1 hoursession_expired, socket closed.
MP4 URL TTL5 minutesresult_expired on result.fetch.

Client SDKs should surface limits from session.ready at runtime — they may be tuned per account.

Error Handling

All errors share this shape:

Error frame
{
"type": "error",
"ref": "msg-1",
"code": "text_too_long",
"stage": "signstream",
"message": "text exceeds max_text_length",
"severity": "message",
"retryable": false,
"retry_after_seconds": null
}
  • ref — the offending message’s id, or empty for pre-session errors.
  • severity:
    • message — one message failed; session continues.
    • warning — transient; session continues, action recommended.
    • session — session is terminated after this error.
  • retryable — safe to resend the same message.
  • retry_after_seconds — wait hint when set.

Error codes

CodeStageSeverityRetryableMeaning
invalid_messagesignstreammessagenoJSON parse failure or unknown top-level type.
invalid_session_startsignstreammessagenoBad session.start payload (missing/invalid field).
unknown_fieldsignstreammessagenoUnrecognised field in a message.
session_not_startedsignstreammessagenoNon-start message sent before session.ready.
text_too_longsignstreammessagenodata exceeds max_text_length.
duplicate_idsignstreammessagenoMessage id already used this session.
rate_limitedsignstreamwarningyesOver max_messages_per_minute. Honour retry_after_seconds.
backpressuresignstreammessageyesOver max_inflight. Retry in ~2s.
result_expiredsignstreammessagenoresult.fetch after 5-minute TTL.
mode_not_allowedsignstreammessagenoMessage not valid in current mode (e.g. result.fetch in stream mode).
session_expiredsignstreamsessionnoSession idle timeout.
internal_errorsignstreammessagenoServer-side failure. Please report with session_id.
gloss_timeouttext_to_glossmessageyesText-to-gloss stage timed out. Retry after 30s.
gloss_unavailabletext_to_glosssessionyesText-to-gloss service down. Retry the session after 30s.
render_failedgloss_translationmessageyesVideo composition failed.
render_timeoutgloss_translationmessageyesRender stage timed out.
encode_failedstream_generatormessageyesFinal MP4 encode failed.

Recommended client behaviour:

  • retryable: true → resend the same message (respect retry_after_seconds).
  • retryable: false → don’t resend; surface to the user.
  • severity: "session" → close and reconnect with a fresh session.start.

Streaming (HLS) Mode

Set mode: "stream" and output_format: "hls" on session.start to receive a continuous HLS stream instead of per-message MP4 URLs. session.ready returns a signed LL-HLS manifest URL (and CloudFront cookies where applicable); subsequent text messages append signs to the ongoing manifest, and playback happens by pointing an HLS player at the manifest URL.

DASH consumers can request a .mpd manifest alongside HLS on the REST POST /v2/generate path — see the REST Quick Start and the Generate endpoint for the manifests object.

Client Implementation Notes

  • Keep-alive — the server does not require application-level pings. Use WebSocket protocol-level pings if the network path has aggressive idle timeouts (>60s intermediary NATs).
  • Reconnection — sessions are not resumable across sockets. Reconnect starts a new session. Use result.fetch on a new session to recover an outstanding MP4 by id, provided the 5-minute TTL has not elapsed.
  • URL handling — download or start playback within 5 minutes. The URL is signed for a specific viewer/session; do not proxy or re-sign it.
  • Concurrency — pipeline up to max_inflight (default 3) messages before waiting for results. Beyond that, expect backpressure.
  • Orderingresult messages may arrive out of order relative to text submission order because pipeline duration varies with text length. Always correlate by ref.
  • Bytes vs charactersmax_text_length is bytes, not characters. UTF-8 non-ASCII characters cost more.
  • Debug flag — set config.debug: true only when actively debugging — it adds extra messages per translation.

Advantages Over V2

FeatureV2V3
Session lifecycleFire-and-forget per socketExplicit session.start / session.end
Per-message correlationNot supportedidref on every downstream frame
Concurrent messagesSerialisedUp to max_inflight (default 3)
Structured errorssuccess: false + message stringTyped code, severity, retryable, retry_after_seconds
Recovery from disconnectNot supportedresult.fetch within 5-minute TTL
Runtime limitsHard-coded on clientSurfaced in session.ready.limits
Timing diagnosticsNot exposedpipeline_ms breakdown on every result
Usage reportingNot exposedsession.summary with billable duration

Beta Notes

  • This is a closed beta of the V3 protocol. Message shapes, defaults, and limits may change; watch the config_applied and limits fields in session.ready rather than hard-coding.
  • Include the session_id from session.ready in any support tickets — it is the primary correlation ID in our logs.
  • Contact your Signapse account contact to request access.
Last updated on
Question? Give us feedback
support@signapse.ai