Local API
Run commands, fire events and follow your stream from your own scripts, over HTTP or a WebSocket
Your script
POST /api/trigger
Host: 127.0.0.1:21424
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"name": "hype",
"data": {
"name": "mochi"
}
}{"ok":true}Events
API trigger
hype
POST /api/trigger fires every mapping whose API trigger has that name.
Drive Vfinity from a script, a stream deck plugin or your own app on the same computer. Send a JSON message to run any app command or fire one of your events, and listen on a WebSocket for gifts, chat and results as they happen.
The Local API shares one server with your OBS overlays, on the overlay port. It answers only programs running on this computer, and only when they carry your access token.
Alpha
Vfinity 2.0 is an alpha, and features may change between builds. Test your integration again after each update, before you go live.
Turn on the Local API
Open the Local server card
Go to SettingsConnections and scroll to Advanced. Open the Local server card. Its status line reads Listening on http://127.0.0.1:21424 when the server is up.
Switch it on
Turn on Enable local API. Vfinity makes an API access token for you the first time.
Copy the token and the addresses
Click Copy under the token and paste it into your script. The card also lists the two addresses to use, the state URL and the WebSocket URL; click either one to copy it.
Generate token replaces the token. Every script still using the old one is disconnected at once, while overlays and your live connections carry on. You can also type your own token: 32 to 256 letters, digits, dashes or underscores.
The port lives in the same card as Shared server port. A new port takes effect after you restart Vfinity. If the port is busy at launch, Vfinity picks another one and the card shows the address it really uses.
This PC
Vfinity connects to the VTube Studio API on port 8001 to press hotkeys and move your model.
Vfinity connects to the WebSocket server built into OBS, port 4455, to switch scenes and show sources.
An OBS browser source opens Vfinity's own server, port 21424, to draw throws, alerts and widgets.
Your scripts reach the Local API on that same port, 21424, with a token.
TikTok LIVE, Twitch, Kick and YouTube are reached over the internet. Vfinity opens each of those connections itself.
Arrow: who opens the connection
Port: who listens for it
How requests are checked
Every HTTP request and every WebSocket connection needs this header:
Authorization: Bearer YOUR_TOKENA request is refused when it comes from another computer, when the token is
missing or wrong, or when it carries a browser Origin header. That last rule
means a web page cannot call the API, even one opened on this computer. Use a
desktop script or tool that can set headers.
Turning on overlay access for OBS on another PC does not open the API to the network, and the overlay access key is not an API token.
Vfinity has to be running for the API to answer. Hidden in the tray counts; after you quit, nothing is listening.
Send a request over HTTP
| Request | Body | Answer |
|---|---|---|
GET /api/state | none | The commands you can run, your events, stream numbers and the TikTok connection |
POST /api/trigger | {"name":"…","data":{…}} | {"ok":true} once the trigger is accepted |
POST /api/command | {"name":"…","args":…} | {"ok":true,"result":…}, or {"ok":false,"error":"…"} |
Send Content-Type: application/json with every POST. Bodies can be up to
64 KiB.
# What can I run?
curl -H "Authorization: Bearer YOUR_TOKEN" http://127.0.0.1:21424/api/state
# Add 30 seconds to the subathon timer
curl -X POST http://127.0.0.1:21424/api/command \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"timer.add","args":30}'$headers = @{ Authorization = "Bearer YOUR_TOKEN" }
# What can I run?
Invoke-RestMethod -Uri http://127.0.0.1:21424/api/state -Headers $headers
# Add 30 seconds to the subathon timer
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:21424/api/command `
-Headers $headers -ContentType "application/json" `
-Body '{"name":"timer.add","args":30}'Fire one of your events
Give an event the API trigger and a Trigger Name, then post that name
to /api/trigger. The name matches without regard to case.
curl -X POST http://127.0.0.1:21424/api/trigger \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"raid_alarm","data":{"message":"Raid incoming","level":3}}'Each field in data becomes a template variable the event's steps can use, so
a speech step with {message} reads "Raid incoming". Text, numbers and true or
false values pass through; nested objects and lists do not. A field name has to
start with a letter, and the first 50 fields count.
The answer {"ok":true} means Vfinity accepted the trigger. An event that is
switched off, paused, or held by its cooldown still does nothing, so listen on
the WebSocket for actionResult if you need to know what ran.
Run a command
Commands are the same named actions hotkeys, Quick Deck pads and command steps
use. GET /api/state lists the ones this build offers right now, because some
only exist while their part of the app is running.
{ "name": "control.panic" }
{ "name": "deck.press", "args": "Applause" }
{ "name": "giveaway.draw" }
{ "name": "sceneCard.showBrb" }
{ "name": "mapping.trigger", "args": "YOUR_EVENT_ID" }mapping.trigger runs one of your events as if its trigger had fired, and
answers with how many runs it started. It takes an event's ID or an API
trigger's name. To get an ID, right-click the event on the Events tab and
choose Copy event ID.
Every command is listed with its argument in Commands.
Connect TikTok LIVE from a script
| Command | Arguments | What it does |
|---|---|---|
tiktok.connect | optional {"username","autoRejoin","waitForLive"} | Connects with your saved settings, overridden for this session only |
tiktok.disconnect | none | Leaves the LIVE and stops reconnecting |
tiktok.cancelRejoin | none | Stops waiting or rejoining, and leaves a joined LIVE connected |
{
"name": "tiktok.connect",
"args": { "username": "yourname", "autoRejoin": true, "waitForLive": true }
}The answer {"ok":true,"result":{"accepted":true}} means the request was
queued, not that the LIVE was joined. Watch the tiktok part of
/api/state, or tiktokStatus on the WebSocket: room.state reads
"connected" once Vfinity is in the LIVE.
Listen on the WebSocket
Connect to ws://127.0.0.1:21424/api/ws with the same Authorization header.
You can send the same requests as over HTTP, each with a requestId you choose,
and Vfinity streams what happens on your stream back to you.
// npm install ws
const WebSocket = require('ws');
const socket = new WebSocket('ws://127.0.0.1:21424/api/ws', {
headers: { Authorization: 'Bearer YOUR_TOKEN' },
});
socket.on('open', () => {
socket.send(JSON.stringify({ type: 'command', name: 'timer.add', args: 30, requestId: '1' }));
});
socket.on('message', (raw) => {
const message = JSON.parse(raw);
if (message.type === 'event' && message.event === 'gift') {
console.log(`${message.data.nickname} sent ${message.data.giftName}`);
}
if (message.type === 'response') console.log(message.requestId, message.data);
});What you send
{ "type": "state", "requestId": "1" }
{ "type": "command", "name": "timer.add", "args": 30, "requestId": "2" }
{ "type": "trigger", "name": "raid_alarm", "data": {}, "requestId": "3" }Each gets one reply: {"type":"response","requestId":"2","data":{"ok":true}}.
What Vfinity sends
Prop
Type
A gift that is part of a combo (giftType 1) sends updates while the combo
runs. Act on it only when repeatEnd is not false, the way Vfinity does.
Timestamps are Unix milliseconds.
The stream is live only: nothing is replayed, and a client that reads too slowly can miss messages.
Limits and errors
| You get | Why |
|---|---|
| HTTP 401 | The token is missing or wrong, or the request had an Origin header |
| HTTP 403 | The request came from another computer |
| HTTP 503 | Enable local API is off |
| HTTP 413 | The body is over 64 KiB |
| HTTP 429 | 16 WebSocket clients are already connected |
"busy" | 32 requests are already waiting for an answer |
"timeout" | No answer within 10 seconds. A command that already started keeps running |
"unknownCommand" | No command by that name is available right now |
"failed" | The command ran and failed; message says why |
"invalidName" | name is missing, empty or longer than 200 characters |
Ordinary backups leave the token out and restore with the API switched off. Tick Include passwords and tokens when you back up to keep it.
Let Vfinity connect to you instead
The Trigger API card, also under Advanced, turns the connection around: Vfinity connects as a client to a WebSocket server you run. It suits a server that already exists, such as a game or a bot.
Your script connects to Vfinity on port 21424, with a token. It can run commands, fire events, read state and receive every live event.
Vfinity connects to your server, by default at localhost on port 8080, with no token. Your server sends triggers and commands and can ask for your API events.
Turn on Trigger API, enter the WebSocket Host and WebSocket Port, then click Connect API. Your server can then send:
{ "type": "trigger", "name": "raid_alarm", "data": { "message": "Raid incoming" } }
{ "type": "command", "name": "timer.add", "args": 30, "requestId": "abc-1" }
{ "type": "request", "requestType": "event_list", "requestId": "abc-2" }A command with a requestId gets an answer such as
{"type":"response","requestType":"command","requestId":"abc-1","data":{"name":"timer.add","ok":true}}.
event_list answers with every event that has an API trigger, its steps and
whether it is on, and stats answers with connection states and event counts.
Anything that can reach your server can run these commands, so keep the server on this computer or put your own authentication in front of it.