Skip to main content
HTTP signaling is in private preview. Contact us to request access.
Your platform proxies stateless HTTP control endpoints for WebRTC signaling and session control. Media (video and audio) flows directly between the end user and Decart over WebRTC. A long-lived Server-Sent Events (SSE) stream carries server-to-client events. A single POST creates the session, exchanges the SDP offer/answer, and optionally sets the initial prompt and reference image — all in one round-trip.

When to use this path

  • Your platform is HTTP-native (REST API gateway, serverless functions, containers)
  • You want white-label endpoints without managing stateful WebSocket connections
  • You want to use standard API gateway tooling (rate limiting, auth, logging)
  • You prefer stateless infrastructure that scales horizontally
This is the recommended path for most API platforms. If you can proxy HTTP, you can integrate Decart realtime.

Characteristics

Media quality is identical to using Decart directly. HTTP signaling adds marginal latency to infrequent control operations — not to the video stream.

Architecture

How it works

1

Create session and exchange SDP

A single POST creates the realtime session, exchanges the SDP offer/answer, and returns ICE server configuration. You can optionally include an initial prompt and reference image to pre-configure the generation before the first frame.Your backend sends the model selection and the client’s SDP offer. Decart returns a 201 Created with the SDP answer, a Location header pointing to the session resource, and an ETag for ICE session tracking.
The sdp object matches the browser’s RTCSessionDescription format. You can pass pc.localDescription directly and apply the response with pc.setRemoteDescription(response.sdp).
The optional fields let you front-load session configuration in the same round-trip:
model
string
required
Model identifier (e.g., lucy-2.1).
sdp
object
required
Client’s SDP offer — { "type": "offer", "sdp": "..." }.
prompt
string
Set the initial prompt before generation starts.
enhance_prompt
boolean
Enhance the prompt automatically (default: true).
image_data
string
Base64-encoded reference image (max 10 MB).
When you include prompt or image_data, the server validates and moderates the content before creating the session. If moderation rejects it, the request fails with 422 — no session is created and no resources are allocated.
The response includes everything needed to complete the WebRTC connection:
session_id
string
required
Unique session identifier.
sdp
object
required
SDP answer — pass directly to pc.setRemoteDescription(response.sdp).
ice_servers
array
required
ICE server configuration — pass to new RTCPeerConnection({ iceServers: response.ice_servers }).
events
object
required
SSE connection details for the server event stream.
expires_at
string
required
ISO 8601 session expiration timestamp.
2

Trickle ICE candidates and open SSE

Right after session creation, forward ICE candidates from the client using PATCH with the If-Match header. The client opens the SSE stream using the event_token from the session response.The candidate format matches RTCIceCandidate.toJSON() — forward them directly from the browser. Signal end-of-candidates by sending a null candidate.
Server-side ICE candidates are delivered via the SSE event stream. The server sends null as the last candidate to signal end-of-candidates from its side.
ETag is required on every PATCH. If you omit If-Match, the server responds with 428 Precondition Required. If the ETag doesn’t match (another ICE operation completed first), you get 412 Precondition Failed — call GET /v1/realtime/sessions/{id} to fetch the current ETag and retry. The server queues concurrent ICE candidates correctly, so rapid-fire PATCHes work as long as each carries a valid ETag.
3

Handle server events (SSE)

The client opens an SSE connection using the event_token from the session creation response. Handle generation lifecycle, server-side ICE candidates, moderation alerts, and errors.
The SSE stream is your only channel for server-initiated messages. Keep it open for the entire session. When the session ends, the server sends generation_ended followed by a final empty data: field, then closes the stream. If the connection drops mid-session, reconnect — EventSource handles this automatically with the Last-Event-ID header. If you reconnect after the session has already ended, the server responds with 410 Gone.
4

Send prompts and images

Control the generation with stateless HTTP calls — no persistent connection needed.
The prompt response echoes back the original prompt text. A 200 status code confirms the content was accepted — no additional success field is needed. Both endpoints moderate input content synchronously — if the content is rejected, the API returns 422 Unprocessable Entity:
Reference images must be under 10 MB (base64-encoded). Requests with oversized images are rejected with 413 Content Too Large.
5

Handle ICE restart (if needed)

If the network path degrades, the server sends an ice-restart SSE event with updated TURN credentials. Respond by creating a new SDP offer (with the provided ICE servers) and sending it as a PATCH with If-Match: "*" (wildcard).
The response includes a new ETag — use it for any subsequent ICE operations.
ICE restarts are server-initiated. The server makes one restart attempt with TURN credentials — if it fails, the session ends with a generation_ended event (reason: "ice_failure").
6

End the session

Explicitly close the session when the user disconnects. The response includes a session summary with billing information.
Sessions also end automatically when:
  • The WebRTC connection fails and ICE restart does not recover it
  • A moderation violation terminates the stream
  • The session reaches the maximum duration
  • No media activity is detected (inactivity timeout)
In all cases, a generation_ended SSE event is sent before the stream closes.

API reference

Endpoints

Session state

Use GET /v1/realtime/sessions/{id} to recover state after reconnects, to fetch the current ETag before retrying a 412 ICE operation, or to obtain a fresh event_token if the SSE connection dropped.
Each GET returns a fresh event_token that expires at the same time as the session. This avoids the need for a separate token refresh endpoint.

Authentication

All control endpoints require an x-api-key header with a valid Decart API key. The SSE endpoint uses a short-lived event_token returned by POST /v1/realtime/sessions (and refreshable via GET /v1/realtime/sessions/{id}):
The event_token is scoped to one session and expires when the session does. This avoids placing your long-lived API key in browser-visible URLs while keeping x-api-key as the upstream authentication method for all other endpoints. The token is ephemeral, read-only (SSE is server-to-client), and safe to pass to the client.

SSE event types

The generation_ended reason field indicates why the session ended:

Error responses

All errors return a structured JSON body:

Provider proxy example

Your control endpoints stay stateless — every request is an independent pass-through, including SSE. The client provides the event_token (received during session creation) to connect to the SSE stream through your proxy.
Your proxy must forward the ETag and Location headers from Decart’s response, and pass through If-Match from client requests. The event_token is ephemeral, session-scoped, and read-only — safe to pass to the client. You can still add your own authentication, rate limiting, and logging on top.

Client implementation

Your client talks to your HTTP proxy for signaling and handles WebRTC with standard browser APIs.
The queue-and-flush pattern batches ICE candidates into fewer PATCH requests while maintaining ETag ordering. In production, retry 412 responses by fetching the current ETag with GET /sessions/{id}.

Next steps

WebSocket Signaling Proxy

Alternative: proxy via WebSocket instead of HTTP

Authentication

API key management and client tokens