> ## Documentation Index
> Fetch the complete documentation index at: https://docs.visualradioassist.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Plain-text routes

> The /api/v2/plain twin of every route answers one flat value, OK or ERR <code>, for panels that cannot read JSON.

Every Core API route exists twice:

* `/api/v2/...` answers JSON.
* `/api/v2/plain/...` answers `text/plain` with one flat value.

Both run the same code, check the same authorization and answer the same status codes. Only the body differs.

## Why plain text

Many control surfaces cannot pick a field out of a JSON body:

* **SKAARHOJ** panels read feedback with one regular expression on the response body. `^(onair|offair|recording)$` against `onair` is easy; against a JSON object it is fragile.
* **Stream Deck** and **Companion** can store a response in a variable or show it on a key, but cannot extract a field.
* Monitoring tools like Zabbix compare one string.

## The rules

| Call | Plain body |
| - | - |
| A read | The value: `onair`, `1`, `ACTIVE`, `Morning Show` |
| A successful action | `OK` |
| A failure | `ERR <code>`, for example `ERR not_found` |

* One line, no trailing newline, no quotes. A regular expression with `^` and `$` matches the whole body.
* Flags are `1` and `0` for signals, macros, camera tally and BOOLEAN variables, and `true` and `false` for `core/active`.
* A camera tally the Core cannot tell is an empty body, not `0`.
* Output statuses and playout phases use an underscore: `on_air`. The studio status does not: `onair`.
* An empty value is an empty body, for example the program title when nothing is on air.
* Errors keep their status code: `ERR unauthorized` comes with `401`, `ERR not_ready` with `503`. See [Errors and status codes](/develop-with-vra/core-control-api/errors-and-status-codes).
* `?wait=0` answers `OK` with status `202`.

## Examples

```bash theme={null}
curl -H "Authorization: Bearer vra_examp1etoken…" \
  http://192.168.1.50:3002/api/v2/plain/studio/status
# onair

curl -H "Authorization: Bearer vra_examp1etoken…" \
  http://192.168.1.50:3002/api/v2/plain/audio-director/off
# OK

curl -H "Authorization: Bearer vra_examp1etoken…" \
  http://192.168.1.50:3002/api/v2/plain/signals/nope
# ERR not_found

curl -H "Authorization: Bearer vra_examp1etoken…" \
  http://192.168.1.50:3002/api/v2/plain/cameras/2/on-air
# 1

curl -H "Authorization: Bearer vra_examp1etoken…" \
  http://192.168.1.50:3002/api/v2/plain/variables/live
# 0
```

## Value per route

| Plain route | Value |
| - | - |
| `/api/v2/plain` | Core version |
| `/api/v2/plain/state` | `rev` of the snapshot: a fingerprint that changes when the content changes |
| `/api/v2/plain/health` | `ok` |
| `/api/v2/plain/clients` | Number of active apps |
| `/api/v2/plain/requests` | Number of logged requests |
| `/api/v2/plain/core` | `ACTIVE`, `DEACTIVATED`, `STARTING`, … |
| `/api/v2/plain/core/state` | `ACTIVE`, `DEACTIVATED`, `STARTING`, … |
| `/api/v2/plain/core/active` | `true` / `false` |
| `/api/v2/plain/studio` | `onair`, `recording` or `offair` |
| `/api/v2/plain/studio/status` | `onair`, `recording` or `offair` |
| `/api/v2/plain/station` | Station name |
| `/api/v2/plain/station/program` | Title of the program on air, empty when none |
| `/api/v2/plain/station/program/title` | Title of the program on air, empty when none |
| `/api/v2/plain/signals` | Number of signals that are on |
| `/api/v2/plain/signals/{id}` | `1` when on, else `0` |
| `/api/v2/plain/signals/{id}/value` | `1`/`0` for BOOLEAN, the number for INTEGER, the text for STRING |
| `/api/v2/plain/audio-director` | `1` / `0` |
| `/api/v2/plain/camera-assist` | `1` / `0` |
| `/api/v2/plain/macros` | Number of macros |
| `/api/v2/plain/macros/{id}` | `1` while it runs, else `0` |
| `/api/v2/plain/macros/{id}/active` | `1` while it runs, else `0` |
| `/api/v2/plain/automations` | Number of automations |
| `/api/v2/plain/automations/{id}` | `standby`, `activated`, `released` or `stopped` |
| `/api/v2/plain/automations/{id}/state` | `standby`, `activated`, `released` or `stopped` |
| `/api/v2/plain/outputs` | Number of outputs on air |
| `/api/v2/plain/outputs/{slot}` | `starting`, `on_air`, `dormant`, `fault` or `offline` |
| `/api/v2/plain/outputs/{slot}/status` | `starting`, `on_air`, `dormant`, `fault` or `offline` |
| `/api/v2/plain/outputs/{slot}/scene` | Key of the scene on air, empty when none |
| `/api/v2/plain/outputs/{slot}/scenes` | Number of scenes the output reports |
| `/api/v2/plain/outputs/{slot}/playout` | Phase of the first playout scene: `standby`, `taking`, `on_air`, `returning` or `holding`; empty when none |
| `/api/v2/plain/cameras` | Number of the camera on air, empty when none |
| `/api/v2/plain/cameras/{id}` | `1` while on air, `0` when not, empty when unknown |
| `/api/v2/plain/cameras/{id}/on-air` | `1` while on air, `0` when not, empty when unknown |
| `/api/v2/plain/cameras/{id}/angles` | Number of angles |
| `/api/v2/plain/angles/{id}` | Angle name |
| `/api/v2/plain/variables` | Number of variables |
| `/api/v2/plain/variables/{name}` | The value, empty when none; `1`/`0` for BOOLEAN |
| `/api/v2/plain/variables/{name}/value` | The value, empty when none; `1`/`0` for BOOLEAN |
| Any control route | `OK` |

See [Routes](/develop-with-vra/core-control-api/routes) for what each route does.

## Matching values on a panel

| Feedback | Plain route | Regular expression |
| - | - | - |
| Studio status | `/api/v2/plain/studio/status` | `^(onair\|offair\|recording)$` |
| Studio on air | `/api/v2/plain/studio/status` | `^(onair)$` |
| Core active | `/api/v2/plain/core/active` | `^(true)$` |
| Audio Director on | `/api/v2/plain/audio-director` | `^([01])$` |
| Signal value | `/api/v2/plain/signals/{id}/value` | `^(.*)$` |
| Macro running | `/api/v2/plain/macros/{id}/active` | `^([01])$` |
| Automation state | `/api/v2/plain/automations/{id}/state` | `^(standby\|activated\|released\|stopped)$` |
| Output on air | `/api/v2/plain/outputs/{slot}/status` | `^(on_air)$` |
| Output status | `/api/v2/plain/outputs/{slot}/status` | `^(starting\|on_air\|dormant\|fault\|offline)$` |
| Scene on air | `/api/v2/plain/outputs/{slot}/scene` | `^(.*)$` |
| Playout phase | `/api/v2/plain/outputs/{slot}/playout` | `^(standby\|taking\|on_air\|returning\|holding)$` |
| Camera tally lamp | `/api/v2/plain/cameras/{id}/on-air` | `^(1)$` |
| Camera tally | `/api/v2/plain/cameras/{id}/on-air` | `^([01])$` |
| Camera on air | `/api/v2/plain/cameras` | `^([0-9]+)$` |
| BOOLEAN variable on | `/api/v2/plain/variables/{name}` | `^(1)$` |
| Variable value | `/api/v2/plain/variables/{name}/value` | `^(.*)$` |

An `ERR …` body never matches the expressions with fixed values, so a failed poll shows no value instead of a wrong one. `^(.*)$` matches any body, an error included; use it only for free text such as a scene key or a variable value.

A tally lamp with `^(1)$` lights only while the camera is on air: `0`, an empty body (tally unknown) and `ERR …` all leave it off.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.