Connectors
A Connector is a project-defined HTTP trigger that bundles a saved sequence of API commands behind a named endpoint, so external systems can drive the show by name (RollSting, LowerThirdOn) rather than re-wiring individual /api/setproperty and /api/invokecommand calls. Connectors can also call an optional OnConnector{Name} script function whose return value shapes the HTTP response — see the Script return-value contract below. For the authoring workflow, see User Guide → Connectors.
GET /api/connector/list
Requires: read (viewer+)
Lists configured API connectors, optionally filtered by running state and group.
IsRunning and TimerMs are live status rather than stored settings: a connector counts as running while
one of its API commands is still animating or waiting out its delay, and TimerMs is how long it has been
running since it was last invoked.
Parameters:
| Parameter | Required | Description |
|---|---|---|
running |
No | true returns only connectors that are currently running, false only idle ones. Omit for all. |
group |
No | Only connectors in this group, matched case-insensitively. Supply it with an empty value (?group=) to select the ungrouped connectors. |
The two filters compose, so ?group=Stings&running=true answers "what is running in this group".
Response: 200 OK — JSON array:
[
{ "Id": "guid", "Name": "My Connector", "Group": "Stings", "IsActive": true, "IsRunning": false, "TimerMs": 0.0, "InvokeCount": 0, "Description": "" }
]
400 Bad Request—runningwas supplied with something other thantrueorfalse
GET /api/connector/stop
Requires: control (operator+) — stopping a connector only unhooks the timers of a sequence already in
flight; it runs no script and reads no settings, so it is not gated at config the way trigger is.
Stops running connectors selected by name, id or group. Stopping freezes an in-flight animation where it stands rather than jumping it to its end value, and cancels the connector's pending delayed commands.
Parameters:
| Parameter | Required | Description |
|---|---|---|
name |
No* | Connector name, matched case-insensitively. |
id |
No* | Connector id (GUID). |
group |
No* | Group name, matched case-insensitively. |
*Exactly one of name, id or group is required. Supplying none or several is rejected rather than
resolved by precedence, so a malformed call cannot silently stop the wrong thing. A selector counts as
supplied when its key is present, whatever its value: ?name=A&group= names two selectors and is
rejected, not treated as a call on name alone. A single selector present but empty (?group=) is also
rejected — unlike /api/connector/list, where ?group= deliberately means "the ungrouped connectors".
There is no "stop everything ungrouped"; use /api/connector/stopall if that is what you want.
Response:
200 OK— JSON:{ "success": true, "matched": 3, "stopped": 2, "connectors": ["Sting"], "message": "Stopped 2 connector(s)" }.matchedcounts the connectors the selector found;stoppedcounts how many of those were actually running. The two differ when a selector matches connectors that were already idle.400 Bad Request— no selector, more than one selector key present, an empty selector, a malformedid, or nothing matched409 Conflict— several connectors share the givenname. Stop byidinstead.
Stopping is complete: a connector that was triggered repeatedly while a delayed or animated command was
still in flight leaves nothing scheduled behind, and does not reappear in ?running=true afterwards.
GET /api/connector/stopall
Requires: control (operator+)
Stops every running connector.
Parameters: None
Response: 200 OK — the same JSON shape as /api/connector/stop, where matched is the total number
of connectors in the project.
GET /api/connector/trigger
Requires: config (editor+) — a connector can run a script (OnConnector{Name}) that reads or writes settings and secrets, so it is gated at config.
Triggers one or more API connectors. If the project's script has an OnConnector{Name} function for the matching connector, its return value shapes the HTTP response (see Script return-value contract below).
Parameters:
| Parameter | Required | Description |
|---|---|---|
name |
No* | Connector name. Trigger several at once by separating them with a literal + — ?name=ConnA+ConnB. Every name given must exist, or the call is rejected and none of them fire. |
value |
No* | Trigger value string |
*At least one of name or value is required.
Additional query parameters (beyond apikey, name, value) are forwarded to the connector as parameters.
Behavior:
- If
ConnectorRestrictionsis set toWarnAndProhibitand a connector is already running, the call is rejected with409 Conflict. - If
ConnectorRestrictionsis set toStopRunningConnectorsInSameGroup, each connector this call invokes first stops the other running connectors that share itsGroup. Connectors in other groups keep running, and a connector with an emptyGroupneither stops others nor is stopped — so grouping stays opt-in and a project that sets no groups behaves as it did before. - For multi-name calls (
name=A+B+C), each connector'sOnConnector{name}runs in turn; the first one that returns a usable value wins as the HTTP response. - The
+is the separator, so escape it inside a name. The value is split on+first and each part is percent-decoded afterwards. A name with a space is written?name=Connector%20%231(one connector,Connector #1); a name that itself contains a plus is written?name=Plus%2BNamed(one connector,Plus+Named). This is the same for a call made over HTTP and one queued from a script or the Test-connector button. - Connectors are dispatched in the order given, and for a
value=match in the order they were created. WithStopRunningConnectorsInSameGroupthat decides the survivor when one call starts several connectors sharing a group: each stops the others in its group as it starts, so the last one dispatched is the one left running. This is dispatch order, not a priority setting. - Case-insensitive. The query parameter keys (
name,value) and the connector name lookup are both matched without regard to case —?Name=Foo,?NAME=foo, and?name=FOOall resolve to a connector namedFoo. - An unusable value on an animated or plain-property command does not fail the call. Where a command animates a property, or writes one whose type is neither text nor a URL, a value that cannot be read as that type is skipped and logged as a warning; the connector's remaining commands still run and the response is unchanged. Text and URL commands are not covered by that rule and can still fail the call. Numbers are read the same way everywhere —
1820.5, with.as the decimal point and no group separator, whatever the machine's language — so a command behaves identically whether it was loaded from the project file or edited in the Desktop since the last save.
Response:
- Custom status / body / content type — when the matching
OnConnector{name}script returns a usable value (see contract below). 202 Accepted— fallbacktext/htmlbodySuccessfully dispatched connector trigger ApiTriggerName: {name}, ApiTriggerValue: {value}when no script returned anything.400 Bad Request— Missing parameters or connector not found409 Conflict— Another connector is already running (when restrictions apply)
Script return-value contract details
The same contract applies to /api/scriptengine/execute. The mapping from the JS function's return value to the HTTP response is:
| Script returns | HTTP response |
|---|---|
string (non-empty) |
200 OK, Content-Type: text/plain, body = string |
| object / array | 200 OK, Content-Type: application/json, body = JSON-serialized value |
object with a numeric httpStatus field, with a body field — explicit envelope { httpStatus, body, contentType? } |
status from httpStatus; body = body (string → text/plain, object → application/json); content type override via optional contentType (full header value, e.g. "Content-type: text/html; charset=utf-8") |
object with a numeric httpStatus field, no body field — hybrid shape { ..., httpStatus } |
status from httpStatus; body = the remaining fields (everything except httpStatus and contentType) serialized as JSON |
undefined, null, empty string, or no return statement |
falls back to the endpoint's default message |
| function not defined / script engine disabled / engine errored | falls back to the endpoint's default message |
Notes:
- A non-numeric
httpStatusvalue is treated as a regular payload field — the whole object is serialized as JSON200 OKand a warning is logged. - An empty body forces the response to
204 No Contentregardless of the requested status (HttpListener behavior). - Status codes pass through verbatim; HttpListener rejects obviously-invalid codes and the endpoint returns
400in that case.
Examples (script function bodies):
// Plain text
function OnConnectorStartDemo() { return "Demo started"; }
// → 200 text/plain "Demo started"
// JSON 200 OK
function OnConnectorListScenes() { return Project.Scenes.map(s => s.Name); }
// → 200 application/json ["Main","Standby"]
// Hybrid: error response with custom status
function OnConnectorShowMultipliers() {
return { result: "error", message: "Demo mode active", httpStatus: 400 };
}
// → 400 application/json {"result":"error","message":"Demo mode active"}
// Explicit envelope: HTML body with custom status
function OnConnectorStatusPage() {
return {
httpStatus: 200,
body: "<h1>Composer is up</h1>",
contentType: "Content-type: text/html; charset=utf-8"
};
}
// → 200 text/html <h1>Composer is up</h1>
GET /api/metadata/send
Requires: control (operator+)
Sends a metadata message via a Vindral CDN Metadata Target.
Parameters:
| Parameter | Required | Description |
|---|---|---|
targetid |
Yes | GUID of the Vindral CDN Metadata Target |
message |
Yes | Metadata message string |
Example:
/api/metadata/send?targetid=guid&message=My metadata message
Response:
200 OK—Metadata sent: {url}400 Bad Request— Missing parameters or target not found