Skip to content

API Examples

The examples sign in, refresh tokens, create a room, create a WebSocket ticket, connect Realtime, read playback state, handle errors, and call Providers in sequence. OpenAPI JSON and protobuf define the complete fields.

Read Client Integration Guide first for the protocol boundaries.

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

Export the schema from a running instance:

终端窗口
curl -fsSL http://localhost:8080/api-docs/openapi.json -o openapi.json

Generate TypeScript types:

终端窗口
npx openapi-typescript openapi.json -o synctv-api.d.ts

See OpenAPI Access for details.

终端窗口
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.

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.

Public gRPC uses the main port:

终端窗口
grpcurl -plaintext localhost:8080 list synctv.client.AuthService

The 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/StartOpaqueLogin

AuthService/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/GetPlayback

Do not expose management gRPC to normal clients.

终端窗口
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.

HTTP error response:

{
"error": "Invalid username or password",
"status": 401,
"code": 1002,
"requestId": "01HX..."
}

Client rules:

  • Use HTTP status for the broad category.
  • Use code for programmatic branches.
  • Log requestId for support.
  • Respect Retry-After on 429.
  • Do not depend on raw 5xx text; it is sanitized.

See Errors.

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