SDK and API Examples
These examples form one runnable chain: login, refresh token, create room, create WebSocket ticket, connect Realtime, read playback state, handle errors, and call Providers. Complete fields are defined by OpenAPI JSON and protobuf.
Read Client Integration Guide first for the protocol boundaries.
Choose an Interface
Section titled “Choose an Interface”| Goal | Interface |
|---|---|
| Generate multi-language SDKs | HTTP OpenAPI |
| Strongly typed backend or desktop clients | gRPC/protobuf |
| Room realtime messages and playback sync | WebSocket Realtime |
| Instance operations | CLI or management gRPC |
| Provider browse, login, proxy | HTTP Provider routes or provider gRPC |
Prepare an OpenAPI SDK
Section titled “Prepare an OpenAPI SDK”Start with OpenAPI enabled:
cargo run -p synctv --features openapi --bin synctv -- serveExport the schema:
curl -fsSL http://localhost:8080/api-docs/openapi.json -o openapi.jsonGenerate TypeScript types:
npx openapi-typescript openapi.json -o synctv-api.d.tsSee OpenAPI Access for details.
Minimal HTTP Flow
Section titled “Minimal HTTP Flow”BASE_URL=http://localhost:8080
curl -sS "$BASE_URL/api/auth/opaque/login/start" \ -H 'Content-Type: application/json' \ -d '{"username":"root","credentialRequest":[/* bytes from your OPAQUE client */]}'Finish the OPAQUE exchange with /api/auth/opaque/login/finish. If the finish response has mfa.required=true, complete MFA before treating the user as logged in. Passwordless email-token login uses /api/auth/email/confirm.
curl -sS "$BASE_URL/api/auth/refresh" \ -H 'Content-Type: application/json' \ -d '{"refreshToken":"paste-refresh-token"}'Replace locally stored tokens after refresh succeeds.
ACCESS_TOKEN=paste-access-token
curl -sS "$BASE_URL/api/rooms" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"name":"Friday Sync","description":"Team movie night"}'Save room.id; HTTP, gRPC metadata, and WebSocket URLs all need it.
ROOM_ID=room_1
curl -sS "$BASE_URL/api/tickets" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d "{\"roomId\":\"$ROOM_ID\"}"The ticket is short-lived, one-time, and room-bound.
Minimal Realtime Flow
Section titled “Minimal Realtime Flow”const ws = new WebSocket(`wss://app.example.com/ws/rooms/${roomId}?ticket=${ticket}`);ws.binaryType = 'arraybuffer';
ws.onmessage = async (event) => { const bytes = event.data instanceof Blob ? new Uint8Array(await event.data.arrayBuffer()) : new Uint8Array(event.data); const message = ServerMessage.decode(bytes); dispatchServerMessage(message);};
function send(message: ClientMessage) { ws.send(ClientMessage.encode(message).finish());}
send({ observeResource: { observeId: 'playback-state', version: cachedVersion ?? '', deliveryMode: 2, playbackState: {}, },});See Realtime API for resource observation, delivery modes, reconnects, and errors.
gRPC Example
Section titled “gRPC Example”Public gRPC uses the main port:
grpcurl -plaintext localhost:8080 list synctv.client.AuthServiceThe public AuthService local password flow uses OPAQUE. Generate the credential request in your client and call StartOpaqueLogin, then finish with FinishOpaqueLogin:
grpcurl -plaintext \ -d '{"username":"root","credentialRequest":"<base64-opaque-request>"}' \ localhost:8080 synctv.client.AuthService/StartOpaqueLoginAuthService/Login is reserved for passwordless email-token login.
Room RPCs need room metadata:
grpcurl -plaintext \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "x-room-id: $ROOM_ID" \ -d '{}' \ localhost:8080 synctv.client.RoomService/GetPlaybackDo not expose management gRPC to normal clients.
Provider Example
Section titled “Provider Example”curl -sS "$BASE_URL/api/providers/instances/available" \ -H "Authorization: Bearer $ACCESS_TOKEN"Alist list request:
curl -sS "$BASE_URL/api/providers/alist/list" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"serverId":"<serverId-from-login-or-binds>","path":"/","instanceName":"alist-main"}'When adding media, the sourceProvider, providerInstanceName, and sourceConfig combination is defined by the Provider. Provider credentials are resolved by the server-side Provider credential layer.
Error Handling
Section titled “Error Handling”HTTP error response:
{ "error": "Invalid username or password", "status": 401, "code": 1002, "requestId": "01HX..."}Client rules:
- Use HTTP
statusfor the broad category. - Use
codefor programmatic branches. - Log
requestIdfor support. - Respect
Retry-Afteron429. - Do not depend on raw 5xx text; it is sanitized.
See Errors.
Idempotency, Retry, and Cache
Section titled “Idempotency, Retry, and Cache”| Operation | Handling |
|---|---|
| Login, MFA, OAuth2 exchange | Do not blindly retry; state or rate limits may be affected |
| Reads | Retry with backoff; use Realtime versions where possible |
| Create room, add media, update settings | On timeout, read back state before repeating |
| WebSocket reconnect | Create a new ticket and rebuild observations |
| Provider request | Back off upstream failures and distinguish credential expiry |