PTZ control WebSocket
The VAPIX® PTZ control WebSocket API provides Pan-Tilt-Zoom control API through a persistent WebSocket connection. This API enables clients to control continuous camera movements.
The API uses a JSON-RPC style communication protocol over WebSocket, established through an HTTP upgrade request. Once connected, clients can send continuous PTZ control commands and receive responses confirming command execution.
A client can use Device Data Hub to subscribe to PTZ specific data hub topics and stream PTZ status. The PTZ control over WebSocket API itself does not support PTZ data polling and instead provides PTZ data streaming over the data hub. The topics provided are:
com.axis.ptz.pan-tilt-state.v1to stream pan tilt datacom.axis.ptz.optical-zoom-state.v1to stream optical zoom data
For more information, see Device Data Hub.
Identification
API discovery
- API Discovery:
id=ptz-control-websocket
WebSocket
- WebSocket Endpoint:
/vapix/ws/v1?apis=ptz-control-ws
Limitations
This API supports cameras with Artpec7 (excluding V59xx) and Artpec9, not Artpec8.
Use cases
Control PTZ over WebSocket
Establish WebSocket connection for PTZ control
To control PTZ operations, a WebSocket connection must first be established using the endpoint: /vapix/ws/v1?apis=ptz-control-ws.
The WebSocket connection starts with an HTTP handshake and upgrades to the WebSocket protocol. The connection authenticates using Digest authentication.
Initial HTTP handshake Request
GET /vapix/ws/v1?apis=ptz-control-ws HTTP/1.1
Host: 192.168.0.90
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Authorization: Digest username="root", realm="AXIS_ACCC8EC43707",
nonce="JrMSij/TBQA=646b1c2c4c0a80a7feb4e34ef9e3422180924c37",
uri="/vapix/ws/v1?apis=ptz-control-ws",
algorithm=MD5, response="683f06da91f927fa1772c42f16597"
Upgrade: websocket
Origin: chrome-extension://cbcbkhdmedgianpaifchdaddpnmgnknn
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: 1L91ICBqd8iwa0I0e6Wgzg==
Successful response:
HTTP/1.1 101 Switching Protocols
Date: Thu, 21 Nov 2025 10:15:30 GMT
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: kZ1kuOZMJmrfKnY8FvL7Tjwb0iw=
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits=15
Query supported API versions
Before sending control commands, query which API versions are supported by the device.
Request:
{
"jsonrpc": "2.0",
"id": "ExampleContext",
"method": "ptz-control-ws_v1:getSupportedVersions",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": "ExampleContext",
"method": "ptz-control-ws_v1:getSupportedVersions",
"data": {
"versions": ["1.0"]
}
}
Query capabilities
Send a control command to a mechanical PTZ camera. This method can be used to look up PTZ ranges and mechanical channel numbers, along with their supported methods and parameters.
Request:
{
"jsonrpc": "2.0",
"id": "ExampleContext",
"method": "ptz-control-ws_v1:getCapabilities",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": "ExampleContext",
"method": "ptz-control-ws_v1:getCapabilities",
"data": {
"channels": [
{
"channel": 1,
"methods": [
{
"name": "continuousMove",
"description": "Initiates continuous movement for the channel",
"parameters": [
{
"name": "channel",
"type": "integer",
"required": true
},
{
"name": "panSpeedDeg",
"type": "number",
"required": false,
"range": {
"min": -180.0,
"max": 180.0
}
},
{
"name": "tiltSpeedDeg",
"type": "number",
"required": false,
"range": {
"min": -180.0,
"max": 180.0
}
},
{
"name": "zoomSpeedNormalized",
"type": "number",
"required": false,
"range": {
"min": -1.0,
"max": 1.0
}
}
]
}
]
}
]
}
}
Perform continuous PTZ movement
Control camera pan, tilt, and zoom in a continuous motion. Continuous moves will stop automatically after 3 minutes to prevent unnecessary wear of the mechanics as long as no further commands are sent. A command must contain at least one of the three before it can be sent.
Request:
{
"jsonrpc": "2.0",
"id": "ptz",
"method": "ptz-control-ws_v1:continuousMove",
"params": {
"channel": 1,
"panSpeedDeg": -20.0,
"zoomSpeedNormalized": 1.0
}
}
Response:
{
"jsonrpc": "2.0",
"id": "ptz",
"method": "ptz-control-ws_v1:continuousMove",
"data": {}
}
API specification
WebSocket connection establishment
PTZ control over WebSocket is performed with the following WebSocket endpoint:
ws(s)://<device-ip>/vapix/ws/v1?apis=ptz-control-ws
- Security level: Admin and Operator. PTZ control is not required.
Authentication
Users need to authenticate themselves in order to use this API. Authentication can be performed in one of two ways:
-
Digest Digest authentication can be achieved by following the standard Digest authentication process. When authentication is performed the connection will be upgraded to a WebSocket connection.
-
Session token As an alternative to Digest authentication it is possible to generate a session token and use the generated token for authentication. This approach can be useful when the client tools don't support Digest authentication.
A session token can be generated by making a
GETrequest to the following URL:http(s)://<device>/axis-cgi/wssession.cgi. This request requires standard Digest authentication.The device will respond with the session token in the payload. This token is valid for 15 seconds and will then expire. The token shall be used in the WebSocket connection URL as a parameter (
wssession) as shown below:ws(s)://\<device\>/vapix/ws/v1?wssession=\<session-token\>&apis=ptz-control-ws
Connection lifecycle
- Client initiates a
HTTP GETrequest with WebSocket upgrade headers - Server responds with
101 Switching Protocolson a successful authentication - Connection is upgraded to WebSocket protocol
- Client can now send
JSON-RPCstyle messages as text packages - Connection remains open until explicitly closed by either party
Access rights
This API can be used by admin and operator users. The account doesn't require explicit PTZ permissions.
getSupportedVersions
Query the API versions supported by the device.
- Security level: Admin and Operator. PTZ control is not required.
Request
{
"jsonrpc": "2.0",
"id": "<string>",
"method": "ptz-control-ws_v1:getSupportedVersions",
"params": {}
}
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| apiVersion | string | Yes | The API version to use for the request. |
| context | string | No | Context identifier for request-response correlation. |
| method | string | Yes | Must be ptz-control-ws_v1:getSupportedVersions. |
| params | object | Yes | Empty object. |
Response - Success
{
"jsonrpc": "2.0",
"id": "<string>",
"method": "ptz-control-ws_v1:getSupportedVersions",
"data": {
"versions": ["1.0"]
}
}
Response fields:
| Field | Type | Description |
|---|---|---|
| apiVersion | string | The API version used by the device. |
| context | string | Echoed context from the request. |
| method | string | Echoed method name. |
| data | object | Response data containing supported versions. |
getCapabilities
The getCapabilities method allows clients to discover mechanical channel numbers, API methods and their supported parameters.
- Security level: Admin and Operator. PTZ control is not required.
Request
{
"jsonrpc": "2.0",
"id": "APD",
"method": "ptz-control-ws_v1:getCapabilities",
"params": {}
}
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| apiVersion | string | Yes | The API version to use for the request. |
| context | string | No | API context identifier. |
| method | string | Yes | Must be ptz-control-ws_v1:getCapabilities. |
| params | object | Yes | Parameters object. |
Response - Success
{
"jsonrpc": "2.0",
"id": "ExampleContext",
"method": "ptz-control-ws_v1:getCapabilities",
"data": {
"channels": [
{
"channel": 1,
"methods": [
{
"name": "continuousMove",
"description": "Initiates continuous movement for the channel",
"parameters": [
{
"name": "channel",
"type": "integer",
"required": true
},
{
"name": "panSpeedDeg",
"type": "number",
"required": false,
"default": 0.0,
"range": {
"min": -180.0,
"max": 180.0
}
},
{
"name": "tiltSpeedDeg",
"type": "number",
"required": false,
"default": 0.0,
"range": {
"min": -180.0,
"max": 180.0
}
},
{
"name": "zoomSpeedNormalized",
"type": "number",
"required": false,
"default": 0.0,
"range": {
"min": -1.0,
"max": 1.0
}
}
]
}
]
}
]
}
}
Response fields:
| Field | Type | Description |
|---|---|---|
| apiVersion | string | API version used by the device. |
| context | string | Echoed context from the request. |
| method | string | Echoed method name. |
| data | object | Response data object containing channels and supported methods. |
| data.channels | array | Array of channel objects. |
| data.channels[].channel | integer | Channel number. |
| data.channels[].methods | array | Array of method objects available on the channel. |
| data.channels[].methods[].name | string | Method name. |
| data.channels[].methods[].description | string | Description of the method. |
| data.channels[].methods[].parameters | array | Array of parameter objects for the method. |
| data.channels[].methods[].parameters[].name | string | Parameter name. |
| data.channels[].methods[].parameters[].type | string | Parameter data type (e.g., integer, number, string, enum, boolean, object). |
| data.channels[].methods[].parameters[].required | boolean | Whether the parameter is required. |
| data.channels[].methods[].parameters[].default | number/string/boolean | Default value if parameter is not provided (optional). For enum types this must be one of the allowed enum values. |
| data.channels[].methods[].parameters[].range | object | Valid range for numeric parameters (optional). |
| data.channels[].methods[].parameters[].range.min | number | Minimum allowed value. |
| data.channels[].methods[].parameters[].range.max | number | Maximum allowed value. |
| data.channels[].methods[].parameters[].enum | array | List of valid values when type is "enum" (optional). |
| data.channels[].methods[].parameters[].enum[] | string | Individual allowed enum value. |
continuousMove
Execute continuous PTZ movement at specified pan, tilt, and zoom speeds. The movement persists until a stop command is issued (using a continuousMove command with a speed of 0.0 to halt the movement, e.g., panSpeedDeg), a new command is given, or a 3-minute timeout occurs to prevent unnecessary mechanical wear.
- Security level: Admin and Operator. PTZ control is not required.
Request
{
"jsonrpc": "2.0",
"id": "<string>",
"method": "ptz-control-ws_v1:continuousMove",
"params": {
"channel": 1,
"panSpeedDeg": -10.0,
"tiltSpeedDeg": -10.0,
"zoomSpeedNormalized": 1.0
}
}
Parameters:
| Field | Type | Required | Valid values | Description |
|---|---|---|---|---|
| apiVersion | string | Yes | "1" | The API version to use for the request. |
| context | string | No | Any string | Context identifier for request-response correlation. |
| method | string | Yes | "ptz-control-ws:continuousMove" | Must be ptz-control-ws_v1:continuousMove. |
| params | object | Yes | - | Parameter object. |
| params.channel | number | Yes | Device dependent | The camera channel number. Retrieves available channels from param.cgi. |
| params.panSpeedDeg | number | No | Device dependent | The pan speed, measured in degrees per second. |
| params.tiltSpeedDeg | number | No | Device dependent | The tilt speed, measured in degrees per second. |
| params.zoomSpeedNormalized | number | No | -1.0 to 1.0 | The normalized zoom speed. Negative values = zoom out, positive values = zoom in. |
Response - Success
{
"jsonrpc": "2.0",
"id": "<string>",
"method": "ptz-control-ws_v1:continuousMove",
"data": {}
}
Response fields:
| Field | Type | Description |
|---|---|---|
| apiVersion | string | The API version used by the device. |
| context | string | Echoed context from the request. |
| method | string | Echoed method name. |
| data | object | Empty object indicating success. |
Response - Error
{
"jsonrpc": "2.0",
"id": "<string>",
"method": "ptz-control-ws_v1:continuousMove",
"error": {
"code": 2104,
"message": "Invalid parameter value specified"
}
}
Error handling
All errors follow a consistent JSON-RPC error structure:
{
"jsonrpc": "2.0",
"id": "<string>",
"method": "<string>",
"error": {
"code": "<integer>",
"message": "<string>"
}
}
General error codes:
| Code | Description |
|---|---|
| 1100 | Internal error |
| 1200 | PTZ not ready |
| 2100 | API version not supported |
| 2101 | Invalid JSON |
| 2102 | Method not supported |
| 2103 | Required parameter missing |
| 2104 | Invalid parameter value specified |
| 2105 | Authorization failed |
| 2106 | Authentication failed |
| 2107 | Transport level error |