The Mavis Camera API uses a WebSocket connection to let another application control the camera, query current camera state, and receive updates when values change.
If you are new to the API, start with the Introduction and try the API Playground first. This page covers the technical details you need when building your own integration.
Connection and API keys
Mavis Camera exposes the API over the local network while the app is open in the foreground.
In Mavis Camera:
- Open Settings.
- Open API.
- Turn on Enable API Access.
- Open URLs to view the addresses available for the API.
The Playground and WebSocket URLs use unencrypted local-network connections, so use them only on a network you trust.
Use the WebSocket URL shown in URLs to establish the API connection from your application. If API keys are enabled, use the URL associated with the API key you want to use.
Using API keys
API keys are optional. For simple testing on a trusted local network, you can leave Use API Keys turned off.
If you turn on Use API Keys, create or enable a key in Mavis Camera and use the URL associated with that key.
A key-specific URL contains the token required to connect. Treat that URL as a secret.
Commands
A command asks Mavis Camera to do something. Commands use a dotted path followed by parentheses.
camerasystem.record.start() focus.mode(manual) exposure.iso(100) colorgrade.matrix.hue(0,0.25)
Commands can have:
- No arguments:
camerasystem.record.start() - One argument:
camerasystem.bars(true) - Multiple arguments:
colorgrade.matrix.hue(0,0.25)
Arguments are positional, so their order matters.
Templates and placeholders
The live API schema describes commands using templates. Braces indicate a placeholder:
focus.value({value})Replace the complete placeholder with the value you want to send:
focus.value(0.5)
Do not include the braces in the command you send.
Argument types
| Type | Value |
|---|---|
bool | true or false |
int | A whole number such as 100 |
float | A finite number such as 0.5 or -1 |
string | Text such as manual, normally selected from the allowed values published by the live schema |
Follow the ranges, allowed values, steps, and units published by the live schema. Some constraints depend on the current camera and configuration.
Calling a command
Send a WebSocket text message containing a JSON call operation.
For example, to show color bars:
{
"call": {
"command": "camerasystem.bars(true)",
"replyTo": "bars-on-1"
}
}replyTo is optional. It is a client-defined string that is copied into the direct response, making it easy to match a response with the request that caused it.
A successful call returns an acknowledgement:
{
"status": "ok",
"command": "camerasystem.bars(true)",
"replyTo": "bars-on-1"
}The returned command is the canonical command. A successful response means the command was accepted and executed.
If your application needs to know the resulting state, query or subscribe to the corresponding state path.
Command errors
A failed call returns status: "error" and an error object:
{
"status": "error",
"command": "focus.mode(unsupported)",
"error": {
"code": "invalidArgumentValue",
"message": "A diagnostic explanation is returned here."
},
"replyTo": "focus-mode-1"
}Use error.code for application logic and error.message for diagnostics.
A rejected request does not close or invalidate the WebSocket session. Correct the request and continue.
Requests are strict. Unknown fields, invalid JSON types, empty required strings, unsupported operations, and invalid command arguments are rejected.
State and events
The API represents camera state as subscribable state paths.
Examples include:
cameraSystem.record.isRecording focus.mode exposure.iso zoom.factor
Use:
queryfor a one-time read.registerStateto receive the current value and future updates.unregisterStateto remove selected subscriptions.clearRegisteredStateto remove every subscription in the current session.
Query a state path
To read the current recording state:
{
"query": {
"path": "cameraSystem.record.isRecording",
"replyTo": "record-state-1"
}
}The response is a mergeable JSON fragment rooted at the requested path:
{
"cameraSystem": {
"record": {
"isRecording": false
}
},
"replyTo": "record-state-1"
}You can merge this fragment into a client-side state tree without replacing unrelated state.
Subscribe to state changes
Register a single path:
{
"registerState": {
"path": "exposure.iso",
"replyTo": "iso-subscription"
}
}Or register several paths together:
{
"registerState": {
"paths": [
"cameraSystem.record.isRecording",
"cameraSystem.bars",
"exposure.iso"
],
"replyTo": "camera-subscription"
}
}Supply path or paths, never both.
The registration response reports the canonical registered paths and their current values:
{
"status": "registered",
"registeredStatePaths": [
"cameraSystem.record.isRecording",
"cameraSystem.bars",
"exposure.iso"
],
"state": [
{
"cameraSystem": {
"record": {
"isRecording": false
}
}
},
{
"cameraSystem": {
"bars": false
}
},
{
"exposure": {
"iso": 100
}
}
],
"replyTo": "camera-subscription"
}The values above are examples. The camera returns its current state.
After registration, a change produces an unsolicited event:
{
"exposure": {
"iso": 200
}
}Unsolicited events do not contain replyTo because they are not direct responses to a request.
Canonical paths and group subscriptions
Use the exact state-path spelling published by discovery.
Command roots and event roots do not always use the same capitalization. For example:
- Command root:
camerasystem - Event root:
cameraSystem
You can subscribe to a leaf such as exposure.iso or to a group such as exposure. A group event contains the available state beneath that group.
Equivalent input spellings are deduplicated, but registrations, responses, and errors use the canonical schema spelling.
A schema-known value may be temporarily unavailable. It can remain registered and begin producing events when it becomes available.
Unsubscribe
Remove one or more paths with unregisterState:
{
"unregisterState": {
"path": "cameraSystem.bars",
"replyTo": "remove-bars"
}
}The response reports removed and remaining paths:
{
"status": "unregistered",
"removedStatePaths": [
"cameraSystem.bars"
],
"registeredStatePaths": [
"cameraSystem.record.isRecording",
"exposure.iso"
],
"replyTo": "remove-bars"
}To clear every registered state path:
{
"clearRegisteredState": {
"replyTo": "clear-all-state"
}
}Subscriptions belong to one WebSocket session. A reconnect creates a new session, so register the state paths you need again after reconnecting.
Discovery
Discovery tells your application what the connected camera supports now.
A client should discover the live schema when it connects instead of permanently embedding a copied list of commands and constraints. Available commands, choices, ranges, and other constraints can depend on the device and its current configuration.
Request the schema
{
"enumerateSchema": {
"mode": "ai",
"includeDynamicConstraints": true,
"replyTo": "schema-1"
}
}All three request fields are optional:
modeacceptsai,compact, ordebugand defaults toai.includeDynamicConstraintsis a Boolean and defaults totrue.replyTois copied into the response when supplied.
Use ai unless your integration has a reason to request another published serialization mode. Keep dynamic constraints enabled when you need the camera's current ranges and allowed values.
What discovery returns
| Section | What it tells you |
|---|---|
roots | Callable command groups, command templates, descriptions, and arguments. |
| Command arguments | Names, types, ranges, steps, units, examples, and allowed values when published. |
stateRoots | Canonical state paths and whether they support query and subscribe operations. |
operations | Supported JSON operations and their request fields. |
types | Published scalar types. |
values | Reusable values when the live schema supplies them. |
The protocol has no version field. Treat the schema response as the authority for the connected camera.
Recommended discovery workflow
- Open the WebSocket connection.
- Request the schema with dynamic constraints enabled.
- Build or validate command controls from
roots. - Build event choices from
stateRoots. - Use each command's
templateand argument metadata. - Use only state paths whose
accessincludes the operation you need. - Register the smallest useful set of state paths.
- Discover and register again after reconnecting.
Command reference
Templates below use braces for argument placeholders. Replace placeholders with values before calling the command.
Camera System
| Command | Arguments | Description |
|---|---|---|
camerasystem.bars({value}) | value — Boolean | Show or hide camera color bars. |
camerasystem.resolution({value}) | value — String | Select the previous or next available camera resolution. |
camerasystem.resolutionid({value}) | value — String | Select an available resolution by ID. |
camerasystem.colorspace({value}) | value — String | Select the previous or next available color space. |
camerasystem.colorspaceid({value}) | value — String | Select an available color space by ID. |
camerasystem.record.start() | None | Start recording. |
camerasystem.record.stop() | None | Stop recording. |
camerasystem.record.toggle() | None | Toggle recording on or off. |
Focus
| Command | Arguments | Description |
|---|---|---|
focus.value({value}) | value — Float | Set the normalized manual focus position. |
focus.mode({value}) | value — String | Select manual or automatic focus mode. |
focus.oneshot() | None | Trigger one-shot autofocus. |
Exposure
| Command | Arguments | Description |
|---|---|---|
exposure.iso({value}) | value — Integer | Set the camera ISO value. |
exposure.gain({value}) | value — Float | Set exposure gain in decibels. |
exposure.gainratio({value}) | value — Float | Set the exposure gain ratio. |
exposure.shutter({value}) | value — Float | Set shutter duration in seconds. |
exposure.shutterangle({value}) | value — Float | Set shutter angle in degrees. |
exposure.bias({value}) | value — Float | Set exposure bias. |
exposure.mode({value}) | value — String | Select manual or automatic exposure mode. |
White Balance
| Command | Arguments | Description |
|---|---|---|
whitebalance.tint({value}) | value — Float | Set white-balance tint. |
whitebalance.temp({value}) | value — Float | Set color temperature in kelvin. |
whitebalance.mode({value}) | value — String | Select manual or automatic white-balance mode. |
whitebalance.scene() | None | Measure the scene and apply white balance from it. |
whitebalance.preset({value}) | value — String | Step through presets or apply the published fixed preset. |
Zoom
| Command | Arguments | Description |
|---|---|---|
zoom.factor({value}) | value — Float | Set the absolute zoom factor. |
zoom.normalised({value}) | value — Float | Set zoom as a normalized value from 0 to 1. |
zoom.servo({value}) | value — Float | Set zoom-servo speed from reverse to forward. |
zoom.reset() | None | Reset zoom to its default value. |
Lens Controls
| Command | Arguments | Description |
|---|---|---|
lenscontrols.lens({value}) | value — String | Select the previous or next supported lens. |
lenscontrols.lensid({value}) | value — Integer | Select a supported lens by ID. |
lenscontrols.stabilize({value}) | value — Boolean | Enable or disable lens stabilization. |
lenscontrols.flip.vertical({value}) | value — Boolean | Enable or disable vertical output flip. |
lenscontrols.flip.horizontal({value}) | value — Boolean | Enable or disable horizontal output flip. |
Tally
| Command | Arguments | Description |
|---|---|---|
tally.red({value}) | value — Boolean | Set or clear the red tally request. |
tally.green({value}) | value — Boolean | Set or clear the green tally request. |
Color Grade
| Command | Arguments | Description |
|---|---|---|
colorgrade.saturation({value}) | value — Float | Set overall saturation. |
colorgrade.reset() | None | Reset the complete color grade. |
colorgrade.lift.r({value}) | value — Float | Set red lift. |
colorgrade.lift.g({value}) | value — Float | Set green lift. |
colorgrade.lift.b({value}) | value — Float | Set blue lift. |
colorgrade.lift.master({value}) | value — Float | Set master lift. |
colorgrade.lift.reset() | None | Reset lift. |
colorgrade.gamma.r({value}) | value — Float | Set red gamma. |
colorgrade.gamma.g({value}) | value — Float | Set green gamma. |
colorgrade.gamma.b({value}) | value — Float | Set blue gamma. |
colorgrade.gamma.master({value}) | value — Float | Set master gamma. |
colorgrade.gamma.reset() | None | Reset gamma. |
colorgrade.gain.r({value}) | value — Float | Set red gain. |
colorgrade.gain.g({value}) | value — Float | Set green gain. |
colorgrade.gain.b({value}) | value — Float | Set blue gain. |
colorgrade.gain.master({value}) | value — Float | Set master gain. |
colorgrade.gain.reset() | None | Reset gain. |
colorgrade.detail.enabled({value}) | value — Boolean | Enable or disable detail processing. |
colorgrade.detail.level({value}) | value — Float | Set the detail level. |
colorgrade.detail.reset() | None | Reset detail processing. |
colorgrade.matrix.enabled({value}) | value — Boolean | Enable or disable matrix color processing. |
colorgrade.matrix.count({value}) | value — Integer | Set the matrix color count. |
colorgrade.matrix.hue({index},{value}) | index — Integer; value — Float | Set the hue for one matrix entry. |
colorgrade.matrix.saturation({index},{value}) | index — Integer; value — Float | Set saturation for one matrix entry. |
colorgrade.matrix.normal() | None | Clear matrix gate and peek inspection. |
colorgrade.matrix.gate({index}) | index — Integer | Show only one matrix color entry. |
colorgrade.matrix.peek({index}) | index — Integer | Highlight one matrix color entry. |
colorgrade.matrix.reset() | None | Reset matrix values. |
Subscribable state reference
Every path below supports both one-time query and ongoing subscription.
Group paths return a mergeable fragment containing their available descendants. Structured means the published schema does not declare a scalar type for that leaf; discover and inspect its live JSON value rather than assuming a fixed shape.
Camera System
| State path | Type | Description |
|---|---|---|
cameraSystem | Group | Complete available camera-system state. |
cameraSystem.record | Group | Available recording state. |
cameraSystem.record.isRecording | Boolean | Whether the camera is currently recording. |
cameraSystem.bars | Boolean | Whether camera color bars are shown. |
cameraSystem.resolution | Structured | Current camera resolution state. |
cameraSystem.availableResolutions | Structured | Resolutions currently available for selection. |
cameraSystem.colorSpace | Structured | Current camera color-space state. |
cameraSystem.availableColorSpaces | Structured | Color spaces currently available for selection. |
Focus
| State path | Type | Description |
|---|---|---|
focus | Group | Complete available focus state. |
focus.value | Float | Current normalized focus position. |
focus.mode | String | Current focus mode. |
Exposure
| State path | Type | Description |
|---|---|---|
exposure | Group | Complete available exposure state. |
exposure.iso | Integer | Current ISO value. |
exposure.gain | Float | Current exposure gain. |
exposure.gainRatio | Float | Current exposure gain ratio. |
exposure.shutter | Float | Current shutter duration. |
exposure.shutterAngle | Float | Current shutter angle. |
exposure.bias | Float | Current exposure bias. |
exposure.mode | String | Current exposure mode. |
White Balance
| State path | Type | Description |
|---|---|---|
whitebalance | Group | Complete available white-balance state. |
whitebalance.tint | Integer | Current white-balance tint. |
whitebalance.temp | Integer | Current color temperature. |
whitebalance.mode | String | Current white-balance mode. |
Zoom
| State path | Type | Description |
|---|---|---|
zoom | Group | Complete available zoom state. |
zoom.factor | Float | Current absolute zoom factor. |
zoom.normalised | Float | Current normalized zoom level. |
Lens Controls
| State path | Type | Description |
|---|---|---|
lensControls | Group | Complete available lens-control state. |
lensControls.lens | Structured | Current lens information. |
lensControls.availableLenses | Structured | Lenses currently available for selection. |
lensControls.stabilize | Boolean | Whether lens stabilization is enabled. |
lensControls.flip | Group | Current output-flip state. |
lensControls.flip.vertical | Boolean | Whether vertical output flip is enabled. |
lensControls.flip.horizontal | Boolean | Whether horizontal output flip is enabled. |
Tally
| State path | Type | Description |
|---|---|---|
tally | Group | Complete available tally state. |
tally.red | Boolean | Current red tally state. |
tally.green | Boolean | Current green tally state. |
Color Grade
| State path | Type | Description |
|---|---|---|
colorGrade | Group | Complete available color-grade state. |
colorGrade.lift | Structured | Current lift values. |
colorGrade.gamma | Structured | Current gamma values. |
colorGrade.gain | Structured | Current gain values. |
colorGrade.saturation | Float | Current overall saturation. |
colorGrade.detail | Structured | Current detail-processing state. |
colorGrade.matrix | Structured | Current matrix color state. |