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
Characteristics
| Property | Value |
|---|---|
| White-label | Yes — end users only see your HTTP URLs |
| Frame access | No — media bypasses your proxy |
| Provider visibility | Full — you see every HTTP request (prompts, images, session events) |
| Client requirements | Browser or native app with WebRTC (no Decart SDK needed) |
| Your infrastructure | Stateless HTTP proxy + one SSE stream per active session |
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
Create session and exchange SDP
A single The optional fields let you front-load session configuration in the same round-trip:The response includes everything needed to complete the WebRTC connection:
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.Model identifier (e.g.,
lucy_2_rt).Client’s SDP offer —
{ "type": "offer", "sdp": "..." }.Set the initial prompt before generation starts.
Enhance the prompt automatically (default:
true).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.Unique session identifier.
SDP answer — pass directly to
pc.setRemoteDescription(response.sdp).ICE server configuration — pass to
new RTCPeerConnection({ iceServers: response.ice_servers }).SSE connection details for the server event stream.
ISO 8601 session expiration timestamp.
Trickle ICE candidates and open SSE
Right after session creation, forward ICE candidates from the client using Server-side ICE candidates are delivered via the SSE event stream. The server sends
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.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.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.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:Handle ICE restart (if needed)
If the network path degrades, the server sends an The response includes a new
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).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").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)
generation_ended SSE event is sent before the stream closes.API reference
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/realtime/sessions | Create session + exchange SDP offer/answer |
PATCH | /v1/realtime/sessions/{id} | Trickle ICE candidates or trigger ICE restart |
GET | /v1/realtime/sessions/{id} | Read session state, current ETag, and refresh event_token |
GET | /v1/realtime/sessions/{id}/events | SSE stream for server events |
POST | /v1/realtime/sessions/{id}/prompt | Set or update the model prompt |
POST | /v1/realtime/sessions/{id}/image | Set reference image (with optional prompt) |
DELETE | /v1/realtime/sessions/{id} | End the session and return billing summary |
Session state
UseGET /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.
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 anx-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
| Event | Data | Description |
|---|---|---|
ice-candidate | {"candidate": "...", "sdpMLineIndex": 0, "sdpMid": "0"} | Server-side ICE candidate — forward to RTCPeerConnection. A null candidate signals end-of-candidates. |
ice-restart | {"ice_servers": [{"urls": "turn:...", "username": "...", "credential": "..."}]} | Server requests ICE restart — reconfigure and send new offer via PATCH |
generation_started | {} | Model is producing frames — media will start flowing |
generation_tick | {"seconds": 30} | Total elapsed generation time in seconds (cumulative, not a delta). Use for usage tracking. |
generation_ended | {"seconds": 120, "reason": "disconnect"} | Session complete. SSE stream closes after this event. |
error | {"type": "...", "title": "...", "detail": "...", "status": 500} | Server error |
generation_ended reason field indicates why the session ended:
| Reason | Description |
|---|---|
disconnect | Client disconnected |
timeout | Session reached the maximum duration |
moderation_violation | Content policy violation terminated the stream |
error | Server error |
insufficient_credits | Account has insufficient credits |
Error responses
All errors return a structured JSON body:| Status | When |
|---|---|
400 | Malformed request body or invalid SDP |
401 | Missing or invalid API key |
404 | Session not found or expired |
410 | Session ended — SSE reconnect after termination |
412 | If-Match ETag doesn’t match current ICE session state |
413 | Image exceeds the 10 MB size limit |
422 | Valid JSON but semantically invalid (unsupported model, content rejected by moderation) |
428 | PATCH sent without required If-Match header |
503 | Service temporarily unavailable — check the Retry-After header |
Provider proxy example
Your control endpoints stay stateless — every request is an independent pass-through, including SSE. The client provides theevent_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}.