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 pertextmessage. 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 onsession.ready; subsequenttextmessages append signs to the ongoing stream.
Connection Details
Connection 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.startmust be the first message. Sending anything else first returnssession_not_started.- Sessions time out after 1 hour of inactivity.
- Up to
max_inflight(default 3)textmessages may be pipelined before waiting forresults. resultmessages may arrive out of order relative totextsubmission order — always correlate byref.
Message Schema
session.start (client → server)
{
"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)
{
"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)
{
"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 asrefon every downstream message. Used to correlatetext.ack/result/errorresponses and for recovery viaresult.fetch. Reusing anidreturnsduplicate_id.data— UTF-8 text, max size in bytes given bylimits.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.
{
"type": "text.ack",
"ref": "msg-1",
"timestamp": "2026-07-16T12:00:00Z"
}result (server → client) — translate mode
The MP4 is ready.
{
"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 andresult.fetchreturnsresult_expired.duration_seconds— video duration.pipeline_ms— server-side timing breakdown across the three pipeline stages; useful for diagnostics.
session.end (client → server)
{ "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.
{
"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:
{ "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.
{
"type": "text.progress",
"ref": "msg-1",
"stage": "gloss",
"status": "complete",
"duration_ms": 120
}Configuration Reference
Fields on the session.start.config object:
config fields
| Name | Type | Required | Description |
|---|---|---|---|
| digital_signer | string | required | The digital signer to render the output. Case-insensitive. Signapse will provide the list of signers available on your account (e.g. "MAX", "RAE"). |
| language | string | optional | British or American Sign Language. Default: "BSL"BSLASL |
| output_format | string | optional | Output video format. For translate mode, leave as "mp4" or omit. For stream mode, use "hls". Default: "mp4" (translate) / "hls" (stream)mp4hls |
| resolution | string | optional | Output resolution. Default: "720p"480p720p1080p |
| debug | boolean | optional | When true, emits text.progress messages for each pipeline stage. Not for production use. Default: false |
| hls | object | optional | 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:
| Limit | Default | Behaviour when exceeded |
|---|---|---|
max_text_length | 5000 bytes | text_too_long error, message rejected. |
max_messages_per_minute | 60 | rate_limited error with retry_after_seconds. Retry after the hint. |
max_inflight | 3 | backpressure error with retry_after_seconds: 2. Wait for outstanding results before sending more. |
| Session idle timeout | 1 hour | session_expired, socket closed. |
| MP4 URL TTL | 5 minutes | result_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:
{
"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’sid, 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
| Code | Stage | Severity | Retryable | Meaning |
|---|---|---|---|---|
invalid_message | signstream | message | no | JSON parse failure or unknown top-level type. |
invalid_session_start | signstream | message | no | Bad session.start payload (missing/invalid field). |
unknown_field | signstream | message | no | Unrecognised field in a message. |
session_not_started | signstream | message | no | Non-start message sent before session.ready. |
text_too_long | signstream | message | no | data exceeds max_text_length. |
duplicate_id | signstream | message | no | Message id already used this session. |
rate_limited | signstream | warning | yes | Over max_messages_per_minute. Honour retry_after_seconds. |
backpressure | signstream | message | yes | Over max_inflight. Retry in ~2s. |
result_expired | signstream | message | no | result.fetch after 5-minute TTL. |
mode_not_allowed | signstream | message | no | Message not valid in current mode (e.g. result.fetch in stream mode). |
session_expired | signstream | session | no | Session idle timeout. |
internal_error | signstream | message | no | Server-side failure. Please report with session_id. |
gloss_timeout | text_to_gloss | message | yes | Text-to-gloss stage timed out. Retry after 30s. |
gloss_unavailable | text_to_gloss | session | yes | Text-to-gloss service down. Retry the session after 30s. |
render_failed | gloss_translation | message | yes | Video composition failed. |
render_timeout | gloss_translation | message | yes | Render stage timed out. |
encode_failed | stream_generator | message | yes | Final MP4 encode failed. |
Recommended client behaviour:
retryable: true→ resend the same message (respectretry_after_seconds).retryable: false→ don’t resend; surface to the user.severity: "session"→ close and reconnect with a freshsession.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.fetchon a new session to recover an outstanding MP4 byid, 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 forresults. Beyond that, expectbackpressure. - Ordering —
resultmessages may arrive out of order relative totextsubmission order because pipeline duration varies with text length. Always correlate byref. - Bytes vs characters —
max_text_lengthis bytes, not characters. UTF-8 non-ASCII characters cost more. - Debug flag — set
config.debug: trueonly when actively debugging — it adds extra messages per translation.
Advantages Over V2
| Feature | V2 | V3 |
|---|---|---|
| Session lifecycle | Fire-and-forget per socket | Explicit session.start / session.end |
| Per-message correlation | Not supported | id → ref on every downstream frame |
| Concurrent messages | Serialised | Up to max_inflight (default 3) |
| Structured errors | success: false + message string | Typed code, severity, retryable, retry_after_seconds |
| Recovery from disconnect | Not supported | result.fetch within 5-minute TTL |
| Runtime limits | Hard-coded on client | Surfaced in session.ready.limits |
| Timing diagnostics | Not exposed | pipeline_ms breakdown on every result |
| Usage reporting | Not exposed | session.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_appliedandlimitsfields insession.readyrather than hard-coding. - Include the
session_idfromsession.readyin any support tickets — it is the primary correlation ID in our logs. - Contact your Signapse account contact to request access.