This guide explains a basic example of how to read and update a device's Outputs shadow using Postman. The same patterns apply to other shadows (System, Inputs, Encoders, Alerts, Containers).
Helpful Tip!
When in doubt, open the LiveEdge® Cloud UI at https://videoncloud.com/ and watch network traffic in your browser's developer tools (F12). The UI’s calls are the gold-standard examples of real payloads and field names.
Table of contents:
- What is a "Shadow"?
- Prerequisites
- Postman Setup
- Key APIs
- Step‑by‑Step: Read & Update the Outputs Shadow
- More Outputs Examples
- Do's and Don'ts (for all Shadows)
- Troubleshooting
- Final notes
- FAQ
What is a "Shadow"?
A shadow is a single-page configuration document persisted to a Videon device. Devices expose multiple shadows, so you can configure independent areas of the device without touching others.
Each shadow tracks two perspectives:
- reported - the current device state (authoritative snapshot produced by the device/Cloud).
- requested - the latest command that was sent for that shadow, along with its status.
You update a shadow by sending a complete replacement of its state list (replace‑by‑list). That's powerful, but it also means you must include all items you want to keep, as anything omitted can be deleted.
Supported shadow_name values: System, Inputs, Encoders, Outputs, Alerts, Containers.
Prerequisites
- A Videon device enrolled in Cloud Control
- Your device's GUID
- A Personal Access Token (PAT)
- API client (Postman is used in this example)
Postman Setup
We'll provide an example for configuring Postman so you can easily create your own Environment and Collection of requests for ease of execution.
1) Create a Postman environment
Create environment variables:
| Variable | Value |
|---|---|
base_url |
https://api.videoncloud.com/v1 |
device_guid |
paste-your-device_guid-here |
PAT |
paste-your-PAT-here |
Enable this environment.
2) Authorization
For each request (or at the Collection level):
-
Auth Type:
API Key -
Key:
Authorization -
Value:
PAT {{PAT}} -
Add to:
Header
This produces an HTTP header:
Authorization: PAT <your-PAT-token>
Key APIs
Get Device Shadow
- https://api.videoncloud.com/v1/openapi/html#operation/GetDeviceShadow
-
GET {{base_url}}/devices/{{device_guid}}/shadows
Optional query parameters:-
shadow_names=Outputs- target a specific shadow -
skip_requested_state=true- hide therequestedblock for a cleaner payload to copy
-
Send Shadow Command
- https://api.videoncloud.com/v1/openapi/html#operation/SendDeviceShadowCommand
POST {{base_url}}/devices/{{device_guid}}/shadows/commands
Body includes yourcommand_type,commands[],target_version, and the fullstate.
Check Shadow Command Status
- https://api.videoncloud.com/v1/openapi/html#operation/GetDeviceShadowCommand
GET {{base_url}}/devices/{{device_guid}}/shadows/commands/{{command_guid}}
Use thecommand_guidreturned by the Send Shadow Command call to track success/failure and completion.
Step‑by‑Step: Read & Update the Outputs Shadow
Step 1: GET the current Outputs shadow
Request
GET {{base_url}}/devices/{{device_guid}}/shadows?shadow_names=Outputs&skip_requested_state=true
Why skip_requested_state=true?
It gives you a cleaner response focused on reported.state and current_version: exactly what you need to prepare a safe update.
Example response (abridged)
{
"shadows": [
{
"shadow_name": "Outputs",
"requested": null,
"reported": {
"state": [
{
"status_message": "Running",
"id": 19,
"status_code": "RUNNING",
"type": "thumbnail",
"config": {
"name": "",
"width": 320,
"interval": 5,
"sources": {
"data": [],
"audio": [],
"video": [
170
]
},
"enable": true
}
},
{
"status_message": "Off",
"id": 173,
"status_code": "OFF",
"type": "rtmp",
"config": {
"name": "RTMP 173",
"service_data": "{\n}\n",
"sources": {
"data": [],
"audio": [],
"video": []
},
"enable": false,
"service_name": "generic"
},
"status": "STREAM_OFF"
}
],
"current_version": 2,
"timestamp": "{timestamp}"
}
}
],
"operation_name": "GetDeviceShadow",
"api_request_id": "{request_id}"
}Record two things:
-
reported.current_version→ you'll needtarget_version = current_version + 1 - The entire
reported.statearray → you'll copy & edit it for your update
Step 2: Prepare your SET payload
A) Modify an existing output (Enable an RTMP output)
Goal: Turn id 173 (RTMP) on.
- Copy the entire
reported.statearray from Step 1. - In the RTMP object (
id: 173), setconfig.enable = true. -
Remove any status fields if present (
status,status_code,status_message, etc.). - Set
target_version = current_version + 1(e.g.,current_version = 2, sotarget_version = 3).
Request
POST {{base_url}}/devices/{{device_guid}}/shadows/commands
POST Body (JSON Payload)
{
"command_type": "set",
"commands": [
{
"shadow_name": "Outputs",
"target_version": 3,
"state": [
{
"id": 19,
"type": "thumbnail",
"config": {
"name": "",
"width": 320,
"interval": 5,
"sources": { "data": [], "audio": [], "video": [170] },
"enable": true
}
},
{
"id": 173,
"type": "rtmp",
"config": {
"name": "YouTube RTMP",
"service_name": "generic",
"service_data": "{\n \"url\": \"rtmp://myrtmpurl/mystreamkey\"\n}\n",
"sources": { "data": [], "audio": [], "video": [] },
"enable": true
}
}
]
}
]
}
Example Response (abridged)
{
"command_type": "set",
"commands": [
{
"shadow_name": "Outputs",
"command_guid": "{command_guid}"
}
],
"operation_name": "SendDeviceShadowCommand",
"api_request_id": "{request_id}"
}Step 3: Track the command by command_guid
Request
GET {{base_url}}/devices/{{device_guid}}/shadows/commands/{{command_guid}}
Poll until the response indicates the command has finished and succeeded (fields may vary by firmware; look for finished: true and success state). If it failed, the response body typically includes a helpful message describing why.
Alternate verification: You can also re‑GET the Outputs shadow and confirm your change is reflected in reported.state. Both patterns are valid.
More Outputs Examples
Create a new RTMP output
To create, append a new object to state. Videon's shadow commands support using "id": false and will assign a real ID upon success. The safest approach is to mirror what the Cloud UI sends for your device generation.
Request
POST {{base_url}}/devices/{{device_guid}}/shadows/commands
POST Body (JSON Payload)
{
"command_type": "set",
"commands": [
{
"shadow_name": "Outputs",
"target_version": <current_version + 1>,
"state": [
/* existing outputs copied from reported.state */,
{
"id": false,
"type": "rtmp",
"config": {
"name": "CDN A",
"service_name": "generic",
"service_data": "{\n \"url\": \"rtmp://example.com/live/abcd1234\"\n}\n",
"sources": { "data": [], "audio": [], "video": [] },
"enable": true
}
}
]
}
]
}
Expected outcome: The command completes; a subsequent GET of the Outputs shadow shows the new output with a real id.
Delete an output
Because the shadow is a full-page replacement, deletion means omitting the object from the submitted state array.
- Start from
reported.state - Remove the object you want to delete
- Submit the new, reduced list
Do's and Don'ts (for all Shadows)
Do:
-
Do copy from
reported.state. It is always the correct and current schema for your device/firmware. -
Do set
target_version = current_version + 1. If you see a conflict, re‑GET, rebase, and try again. -
Do use
skip_requested_state=truequery parameter when sending theGET; you'll receive a cleaner body for copy/paste. -
Do poll
GET …/shadows/commands/{command_guid}to confirm completion and success; log or surface failures to operators. - Do keep changes minimal. Change only the fields you intend to update.
-
Do treat
stateas authoritative. Include everything you want to keep; this prevents accidental deletions. - Do test first before deploying changes to devices in Production.
Don't:
-
Don't include
statusfields (status,status_code,status_message, etc.) in yourstatepayload; they are read‑only reporting fields. -
Don't invent fields or change object shapes; mirror the structure you
GET. -
Don't reuse a stale
target_version. If someone else updated the shadow, your version may be out‑of‑date. - Don't submit a partial list when you intend to preserve existing components; omitted entries can/will be deleted.
-
Don't assume creation ID rules. Use
"id": false; confirm with a follow‑upGET.
Troubleshooting
-
401/403 Unauthorized
- Confirm
Authorization: PAT <token>header is present. - Verify the PAT is valid and hasn’t been revoked.
- Confirm
-
Error 500 Config mismatch! from response of the GET to the command_guid
- This means the response from the device does not exactly match the requested changes. Monitor the response from the device to ensure that the configurations that were set match the expected outcome.
- We've identified a known software bug that requires components to be named in the shadow commands. Be sure all inputs, encoders, or outputs you create via shadow commands have a valid entry in the
"name"field.
-
400 Validation error
- Server could not process the request, usually due to a missing or incorrectly formatted parameter. Check the response body for a message and/or error code, edit minimally, and retry.
-
Command finished but output didn't start
- Check the device's
reported.stateand anystatus_message. Destination reachability, input or encoder dependencies can keep outputsOFF.
- Check the device's
-
Creation didn't assign an ID
- Verify your creation pattern aligns with the UI's. Try
"id": false, then re‑GETto discover the assignedid.
- Verify your creation pattern aligns with the UI's. Try
Final notes
Device shadows can be confusing at first glance, but the above examples can be expanded to configure many outputs or other settings on Videon devices, via just a couple LiveEdge Cloud API calls. If you run into issues please reach out to Tech Support and Videon can help get your workflow unblocked!
To advance to the next level of shadow commands, feel free to advance to the following article: How to control Videon devices with Shadows 201
FAQ
How do I create/delete a component (an output, encoder, input, etc.)?
Since shadows are single-page configurations, all that needs to be done to both create and delete components is to either include the new desired with id: false, or not include any non-desired components in the Body of the POST request, and the shadow will be applied, either adding the newly included components or removing the excluded components.
This is useful in reducing the number of calls needed to be made when configuring multiple components, but be careful not to accidentally delete a component by not including it in the shadow, even if it is not receiving any new changes!
What are the options for components that can be configured via Shadows?
Since we are often adding new options and features to LiveEdge Cloud's capabilities, the best way to know the current possible options for any component/function is to use our Cloud UI with the browser console open (F12 in Chrome) and mimic the calls that our UI makes to the LiveEdge Cloud API.