VConnect exposes a WebSocket server (enable it in Settings → WebSocket) that external tools can use
to query and control the running instance in real time, and to receive live events. The wire format
is deliberately close to the older T.I.T.S. API — same envelope
shape and Request/Response/Event naming convention — so existing TITS integrators have a head
start. It isn't a strict clone: VConnect uses its own uid identity convention throughout instead of
TITS's ID/itemID/triggerID.
Every message — request, response, or broadcast event — is a JSON object with these fields:
{
"apiName": "VConnectPublicApi",
"apiVersion": "1.0",
"requestID": "some-id",
"messageType": "TriggerListRequest",
"timestamp": "2026-07-30T18:04:12.000Z",
"data": { }
}requestID— client-supplied on requests; the server echoes the same value back on the matching response, so you can correlate replies to requests (and, if you ever need it, dedupe). Broadcast events aren't replies to anything, so they carry a fresh, server-generatedrequestID.messageType— discriminates what kind of message this is. See the full list below.timestamp— UTC, ISO-8601.data— payload, shape depends onmessageType.
Responses are sent only to the client that sent the request (not broadcast). Broadcast events go out to every connected client.
Fires a trigger on demand — equivalent to clicking "Test" on it in the UI, but without cancelling any other run already in flight on that trigger's graph.
// → request
{
"messageType": "TriggerActivateRequest",
"requestID": "1",
"data": {
"uid": "a0ce3831-3c3e-4474-b4e4-19ab98dc73dd"
}
}data.uid or data.name identifies the trigger (either works; uid is checked first).
// ← response
{
"messageType": "TriggerActivateResponse",
"requestID": "1",
"data": {
"uid": "a0ce3831-3c3e-4474-b4e4-19ab98dc73dd",
"name": "New Follow",
"success": true,
"error": null
}
}The response acknowledges that the trigger was found and started — it does not wait for the fired
graph to finish (some triggers loop or wait indefinitely). Watch for TriggerActivatedEvent/
TriggerEndedEvent (below) if you need the full lifecycle.
Lists every trigger in the active profile.
// → request
{
"messageType": "TriggerListRequest",
"requestID": "2"
}// ← response
{
"messageType": "TriggerListResponse",
"requestID": "2",
"data": {
"triggers": [
{
"uid": "a0ce3831-3c3e-4474-b4e4-19ab98dc73dd",
"name": "New Follow",
"enabled": true,
"nodeCount": 7
},
{
"uid": "ebb7170b-40e6-4832-8b05-bc6c809d79f1",
"name": "Throw Bananas",
"enabled": true,
"nodeCount": 12
}
]
}
}Lists every asset in the library.
// → request
{
"messageType": "AssetListRequest",
"requestID": "3",
"data": {
"includeScreenshots": false
}
}data.includeScreenshots (default false) — set true to embed a base64 PNG per asset. This can be
slow for a large library (each 3D/VRM asset may need to render a fresh snapshot), so it's opt-in.
// ← response
{
"messageType": "AssetListResponse",
"requestID": "3",
"data": {
"assets": [
{
"uid": "60c678fc-60d1-4740-92d8-30f8bf42afc9",
"name": "apple",
"type": "ThreeDObjectAsset"
},
{
"uid": "16d75b54-f4f4-4f97-a946-8ddb21eb2820",
"name": "banana",
"type": "PNGAsset"
}
]
}
}Gets details for a single asset by uid, optionally with a screenshot.
// → request
{
"messageType": "AssetInfoRequest",
"requestID": "4",
"data": {
"uid": "60c678fc-60d1-4740-92d8-30f8bf42afc9",
"includeScreenshot": true
}
}// ← response
{
"messageType": "AssetInfoResponse",
"requestID": "4",
"data": {
"uid": "60c678fc-60d1-4740-92d8-30f8bf42afc9",
"name": "apple",
"type": "ThreeDObjectAsset",
"screenshot": "iVBORw0KGgoAAAANSU..."
}
}screenshot reuses the asset's cached preview when available; otherwise a fresh one is rendered on
the spot. Screenshot support currently covers 3D/VRM model assets (rendered via the in-editor preview
camera) and PNG assets (their own texture, directly). Other asset types (GIF, audio, video, particle
systems) return screenshot: null.
Sent instead of the expected ...Response when a request is malformed, names an unknown
messageType, or references something that doesn't exist:
{
"messageType": "ErrorResponse",
"requestID": "4",
"data": {
"message": "No asset found with uid '...'."
}
}These go out to every connected client — not replies to a specific request.
Fired whenever a trigger starts and finishes running, from any source — a real event (Twitch
follow, YouTube super chat, etc.), a manual "Test" click in the UI, or a TriggerActivateRequest.
{
"messageType": "TriggerActivatedEvent",
"data": {
"uid": "a0ce3831-3c3e-4474-b4e4-19ab98dc73dd",
"name": "New Follow"
}
}{
"messageType": "TriggerEndedEvent",
"data": {
"uid": "a0ce3831-3c3e-4474-b4e4-19ab98dc73dd",
"name": "New Follow",
"success": true,
"error": null
}
}Fired when a spawned item appears, is hit, and is removed — VConnect's equivalent of TITS's
TITSHitEvent family. triggerUid/triggerNodeUid identify which trigger (and which specific
trigger node inside it) caused the item to spawn in the first place; both are null when there's no
trigger involved (e.g. a manual spawn from the UI, or a Test() run with no trigger node upstream).
{
"messageType": "AssetSpawnEvent",
"data": {
"itemUid": "d1a7f8d2-...",
"itemName": "banana",
"triggerUid": "ebb7170b-...",
"triggerNodeUid": "3fa2..."
}
}{
"messageType": "AssetHitEvent",
"data": {
"itemUid": "d1a7f8d2-...",
"itemName": "banana",
"triggerUid": "ebb7170b-...",
"triggerNodeUid": "3fa2...",
"point": {
"x": 0.1,
"y": 0.4,
"z": 0.0
},
"normal": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"relativeVelocity": {
"x": 0.33,
"y": 0.93,
"z": 0.19
},
"forceEstimate": 24.5
}
}{
"messageType": "AssetDespawnEvent",
"data": {
"itemUid": "d1a7f8d2-...",
"itemName": "banana",
"triggerUid": "ebb7170b-...",
"triggerNodeUid": "3fa2..."
}
}Beyond the built-in calls above, node graphs can send and receive arbitrary custom messages via the
Send WebSocket Message and On WebSocket Receive nodes. These always use messageType: "websocket_node", with the payload shaped as { "channel": string, "data": [...] }:
{
"messageType": "websocket_node",
"data": {
"channel": "my-event",
"data": [
"arg1",
42,
true
]
}
}Send a message in this exact shape to trigger a matching On WebSocket Receive node (filtered by
channel) in any running graph. This is the escape hatch for anything project-specific that doesn't
warrant a built-in API call.
More broadcast event types will land here as they're added. If you're integrating against this API and find yourself wanting an event or call that doesn't exist yet, you can always ask me for changes!