Implementation reference
Net-X-Router REST API
This page documents the HTTP commands implemented by the current Net-X-Router service.
The primary control endpoint is /config. Most operations use an
action, a paramid, and an optional value in the query string.
Audited against the Net-X-Router source on 2026-07-20.
Quick start
/heartbeat{"alive":true,"service":"netxrouter","status":"ok"}
/config?action=get¶mid=eParamID_StatusAllReturns all 16 input slots, their basic transport analysis, redundancy state, and their destination slots.
/config?action=set¶mid=eParamID_XPT_Destination1_Status&value=3In traditional routing mode, connects Source 3 to Destination 1. Use value=0 to disconnect it.
{"name":"eParamID_XPT_Destination1_Status","value":"3","value_name":"3"}
/config?action=get_events&after=0&limit=100Returns the latest router events and a sequence cursor for subsequent polling.
Request contract
| Item | Contract |
|---|---|
| Base URL | http://<router-host>:<http-port> |
| Method | The current UI and examples use GET. The callback reads commands from the request URI query string. |
| Parameter endpoint | /config?action=get|set¶mid=<id>&value=<value>. Legacy parameter clients may use /options with the same query. |
configid | Legacy clients send configid=0. It is accepted but not used by Net-X-Router. |
| Encoding | Percent-encode every query value. This is essential for JSON, URLs, ampersands, passwords, spaces, and license keys. |
| Indexing | Route, setup, monitor, analyzer selection, and button parameter IDs are 1-based. The index field inside StatusAll is 0-based. |
| Response format | Most responses are compact JSON. Several compatibility operations deliberately return plain text such as ok, true, or 16. |
| Unknown command | Usually returns HTTP 200 with {} or a generic empty-value object. Validate the body; do not treat HTTP 200 alone as command success. |
Endpoint index
| Command | Purpose | Response |
|---|---|---|
GET /heartbeat | Lightweight liveness check | JSON object |
GET /config?heartbeat=1 | Heartbeat compatibility form | JSON object |
action=connect | Legacy UI connection handshake | {"connectionid":"42"} |
action=get | Read a parameter | Parameter-specific |
action=set | Write a parameter | Parameter-specific |
action=wait_for_config_events | Consume queued UI configuration changes | JSON array |
action=get_events | Search or incrementally poll the event history | JSON object |
?license | Read license state | JSON object |
?version | Read current/latest version information | JSON object |
?generateSiteCode | Generate a site code | Plain text |
?registerLicenseKey | Register a license key | Plain true/false |
?directoryPassword | Set web directory Basic Auth password | Plain ok/fail |
/options is a compatibility alias for general action=connect|get|set parameter requests. Use /config for new clients and for heartbeat, events, and configuration-event polling. /descriptors has one special compatibility response documented under Signal switching.
Health and system
/heartbeat/config?heartbeat=1Both forms are independent of stream/router state and return the same body:
{
"alive": true,
"service": "netxrouter",
"status": "ok"
}
/config?action=connectCompatibility handshake used by the web parameter framework. The connection ID is currently fixed.
{"connectionid":"42"}
/config?action=get¶mid=eParamID_SysNameReturns the plain text service name:
netxrouter
Events
/config?action=get_events&after=<sequence>&limit=<1..500>&severity=<name>&query=<text>This is the non-destructive, searchable event feed used by the Events page.
| Query | Default | Meaning |
|---|---|---|
after | 0 | With zero, return the latest matching events. Otherwise return matching events whose sequence is greater than this cursor. |
limit | 100 | Number of results, clamped to 1 through 500. |
severity | all | Exact, case-insensitive severity name: debug, info, warning, or error. Empty and all disable this filter. |
query | empty | Case-insensitive substring match against the compact JSON representation of each event. |
{
"available": true,
"events": [ ... ],
"oldest_sequence": "1",
"latest_sequence": "84",
"next_sequence": "84",
"has_more": false,
"history_capacity": 2000,
"truncated": false
}
If event initialization failed, the response also contains error. If truncated is true, the requested cursor predates the oldest event still retained.
Event object
| Field | Type | Description |
|---|---|---|
sequence | decimal string | Router-local polling sequence. |
event_id | decimal string | dtEvents numeric event ID. |
event_type | string | For example source.missing, source.restored, source.ts_problem, destination.connected, or button.lock_changed. |
source_id, source_name | string | Originating router object. |
message | string | Displayable description. |
severity, severity_name | number, string | Numeric dtEvents severity and normalized name. |
action, dedupe_key, correlation_id | string | Lifecycle/search metadata. |
utc_ns, ptp_ns, pts, duration_ms | decimal string | High-range integer values are strings to avoid JSON number precision loss. |
utc_iso | string, optional | UTC ISO-8601 timestamp when utc_ns is nonzero. |
timecode, units | string | Optional media/value context. |
value, threshold | number | Optional measured and threshold values. |
details_json | string | Original dtEvents details JSON. |
details | object/array, optional | Parsed form of details_json when valid. |
/config?action=wait_for_config_eventsLegacy UI configuration-event queue. It returns an array and removes the returned events from the queue.
[
{"param_id":"eParamID_XPT_Source1_Line_1","str_value":"Camera 1"},
{"param_id":"eParamID_XPT_Destination1_Locked","int_value":1}
]
wait_for_config_events is destructive. Use get_events for the searchable router event history.Parameter API
All parameter commands use this canonical form:
GET /config?action=get&configid=0¶mid=<parameter-id>
GET /config?action=set&configid=0¶mid=<parameter-id>&value=<percent-encoded-value>
The tables below use N for a 1-based source or destination number from 1 through 16 and L for button label line 1 or 2.
Routing
Traditional mode
eParamID_XPT_DestinationN_StatusGet the 1-based source routed to Destination N. Value 0 means no source.
action=set¶mid=eParamID_XPT_DestinationN_Status&value=<source>Route the destination to a source, or disconnect with value=0.
{
"name": "eParamID_XPT_Destination1_Status",
"value": "3",
"value_name": "3"
}
If a locked destination rejects the change, the response retains the current route and adds "locked":true.
Multi-output mode
eParamID_XPT_SourceN_StatusReturns the configured destination map for Source N.
action=set¶mid=eParamID_XPT_SourceN_Status&value=<source>,<destination>,<true|false>Enable or disable one source/destination connection. Both numbers in the CSV value are 1-based. The parameter's N should match the source in the value.
{
"name": "eParamID_XPT_Source2_Status",
"value": {
"1": {
"enabled": true,
"disabled": false,
"disable": false,
"url": "srt://192.168.50.80:9000?mode=caller",
"type": 3
}
}
}
A rejected locked-destination change adds "locked":true.
Compatibility detail: in this response, each connection's url and type currently echo the source input URL/type. Use eParamID_StatusAll when destination URL/type values are required.
Destination locking
eParamID_XPT_DestinationN_Lockedaction=set¶mid=eParamID_XPT_DestinationN_Locked&value=<0|1>{"name":"eParamID_XPT_Destination1_Locked","value":true}
A locked destination rejects route changes in both router modes. Setting the value to 0 unlocks it.
Router mode
/config?action=get¶mid=eParamID_XPT_ChangeRouterMode0/config?action=get¶mid=eParamID_XPT_ChangeRouterMode1The mode is encoded in the parameter ID: 0 is traditional and 1 is multi-output. The service reloads saved settings for the selected mode and returns plain text ok.
Input/output setup
action=set¶mid=eParamID_SetupIO_Source_N&value=<json>action=set¶mid=eParamID_SetupIO_Destination_N&value=<json>The setup value is a percent-encoded JSON object:
{
"type": 3,
"url": "srt://192.168.50.80:9000?mode=caller&latency=120",
"disabled": false
}
| Field | Type | Meaning |
|---|---|---|
type | integer or numeric string | Protocol type ID from the protocol table below. |
url | string | Complete transport or file URL. The URL scheme selects the transport implementation. |
disabled | boolean/number/string | Only applied to file sources/destinations. disable is accepted as a compatibility alias. |
A successful update returns plain text ok. Reconfiguring a source preserves its configured destination relationships.
Remove an input or output
Send the same setup parameter with an empty URL:
{"type":10,"url":"","disabled":false}
Source removal disconnects and destroys the source. Destination removal is implemented for traditional mode.
get request currently returns plain ok, not the saved configuration. Read current setup from eParamID_StatusAll.Percent-encoding example
const value = encodeURIComponent(JSON.stringify({
type: 3,
url: "srt://192.168.50.80:9000?mode=caller&latency=120",
disabled: false
}));
fetch("/config?action=set&configid=0¶mid=eParamID_SetupIO_Source_1&value=" + value);
Status and usage
/config?action=get¶mid=eParamID_StatusAllReturns an array with exactly one object for each input slot. The top-level input index is 0-based.
[
{
"index": 0,
"status": 3,
"type": 10,
"disabled": false,
"disable": false,
"url": "file:///G:/test.ts?loop=1",
"datarate": 18,
"analysis": { ...basic analyzer object... },
"redundancy": {"enabled":false},
"destinations": [
{
"status": 4,
"status_msg": "",
"enabled": true,
"type": 2,
"url": "rtp://239.1.1.1:5000",
"datarate": 18,
"disabled": false,
"disable": false,
"redundancy": {"enabled":false}
}
]
}
]
Unconfigured inputs contain only index and status:0. A source in the illegal state can also include status_msg. Destination arrays contain 16 entries when the source is configured; optional configuration fields appear when that source/destination pair exists.
Basic analyzer object
Each active input is analyzed on a separate best-effort, low-priority path. StatusAll.analysis is a cached snapshot refreshed at most four times per second.
| Field | Type |
|---|---|
enabled, locked | boolean |
analysis_level | off, basic, or full |
packets, bytes, sync_errors, transport_errors, continuity_errors, duplicate_packets, missing_packets, problem_count | decimal string |
duration_sec, bitrate_mbps, packet_rate | number |
program_count, stream_count, video_streams, audio_streams, metadata_streams | integer |
codecs | array of unique codec display names |
streams | array of {program_number,pid,pid_hex,category,codec_name} |
/config?action=get¶mid=eParamID_Usage{"cpu":12,"mem":123456789,"netIn":66,"netOut":28}
cpu is system CPU use, mem is the system-used-memory value reported by the platform helper, and netIn/netOut are aggregate router data rates in Mbps.
/config?action=get¶mid=eParamID_ButtonsPerTypeReturns the maximum source count and destination count as plain text. The current value is:
16
Transport stream analyzer
The selected analyzer uses full TS analysis. It is independent of the selected route and the web monitor source.
eParamID_TsAnalyzeSourceaction=set¶mid=eParamID_TsAnalyzeSource&value=<0..16>Select a 1-based input. Value 0 closes/disconnects the selected analyzer.
{"name":"eParamID_TsAnalyzeSource","sourceIndex":4,"value":"4"}
eParamID_TsAnalyzeConfigaction=set¶mid=eParamID_TsAnalyzeConfig&value=<0|1>Enable or disable full analysis for the selected source. The setting is persistent and defaults to enabled.
{"name":"eParamID_TsAnalyzeConfig","value":"1","enabled":true}
eParamID_TsAnalyzeStatus{
"name": "eParamID_TsAnalyzeStatus",
"sourceIndex": 4,
"source": {
"index": 4,
"input": { ...full analyzer object... }
}
}
If no configured input is selected, source is omitted.
Full analyzer object
The object under source.input contains:
| Group | Fields |
|---|---|
| State/counters | enabled, analysis_level, locked, packets, bytes, sync_errors, transport_errors, continuity_errors, duplicate_packets, missing_packets, problem_count |
| Transport | transport_stream_id, pat_version, duration_sec, bitrate_mbps, packet_rate |
| Programs | programs[] with program_number, PMT/PCR PIDs in decimal and hex, pmt_version, program descriptors[], components[], and optional PMT/PCR stats. |
| Components | PID, stream type, category, codec identifiers/display name, registration, language(s), parsed details, descriptors, and optional PID stats. |
| All PIDs | pids[] and optional null_pid. |
PID statistics object
{
"pid": 256,
"pid_hex": "0x0100",
"packets": "12345",
"bytes": "2320860",
"payload_packets": "12000",
"adaptation_packets": "345",
"continuity_errors": "0",
"duplicate_packets": "0",
"missing_packets": "0",
"discontinuities": "0",
"scrambled": false,
"has_pcr": true,
"pcr_jitter_ms": 0.04,
"pcr_drift_ms": 0.12
}
Descriptor-derived details vary by stream. They can include video profile/level, frame dimensions and rate, scan type, audio layer/profile/channel configuration, ISO-639 language/audio type, AC-3/E-AC-3 properties, caption services, component names, and registration identifiers.
Web monitor control
These commands control which router input feeds the fixed WebRTC monitor. WebRTC signaling and media are served by the dtx_webrtc output on the separate port returned by MonitorStatus; they are not served by the REST port.
eParamID_MonitorSourceaction=set¶mid=eParamID_MonitorSource&value=<0..16>Select a 1-based input. Value 0 closes the monitor output.
{"sourceIndex":1}
eParamID_MonitorConfigReturns whether the monitor output exists. Configuration is automatic; a set currently has no additional effect.
{"active":true}
eParamID_MonitorStatus{
"sourceIndex": 1,
"active": true,
"status": 4,
"webrtcPort": 9100,
"processingActive": true,
"videoFramesSent": 1523,
"audioFramesSent": 3046,
"ringBytesDropped": 0,
"tsBytesReceived": 28492340,
"ringDropEvents": 0,
"maxRingDropBytes": 0,
"ringBytesAvailable": 1316,
"lastVideoFrameAgeMs": 16,
"lastAudioFrameAgeMs": 8,
"sourceUrl": "file:///G:/test.ts?loop=1",
"sourceType": 10,
"sourceStatus": 3,
"sourceDatarate": 18
}
The processing/ring/frame fields appear only while the monitor output exists. The source fields appear only while a valid configured input is selected. Frame ages are -1 until the corresponding media type has been produced.
http://<router-host>:<webrtcPort>/webrtc.Licensing and web access
/config?license{
"status": "1",
"temporary": "False",
"option": "0",
"optionstring": "",
"description": "Registered on ..."
}
/config?version{
"currentVersion": "8.0.123",
"newestVersion": "8.0.124",
"needsUpdate": "1",
"updateURL": "...",
"updateDescription": ["..."]
}
/config?generateSiteCode&username=<name>&email=<email>Returns the generated site code as plain text.
/config?registerLicenseKey&key=<key>Returns plain text true when registration succeeds, otherwise false.
/config?directoryPassword&password=<password>Creates/updates the web directory's Basic Auth files for user admin. Returns plain text ok or fail.
Shared values
Stream status
| Value | Name | Meaning |
|---|---|---|
| 0 | Off | No threads/no signal. |
| 1 | Waiting | Waiting for an input signal or peer. |
| 2 | Connected | Transport connected. |
| 3 | Receiving | Input data is being received. |
| 4 | Sending | Output data is being sent. |
| 5 | Closing | Transport is closing. |
| 6 | Illegal | Invalid configuration or transport error; inspect status_msg. |
Protocol type IDs
| ID | Protocol | Input | Output | Notes |
|---|---|---|---|---|
| 1 | UDP transport stream | Yes | Yes | udp:// |
| 2 | RTP transport stream | Yes | Yes | rtp:// |
| 3 | SRT | Yes | Yes | Caller/listener and two-link redundancy. |
| 4 | RIST | Windows | Windows | rist:// |
| 5 | Zixi | Licensed build | Traditional/Windows build | Compile-time and SDK/license dependent. Multi-output output factory does not currently create Zixi. |
| 6 | TCP | No | No | Reserved for a future uncompressed transport; do not configure. |
| 7 | HLS | Yes | Yes | hls:// |
| 8 | RTMP | Yes | Yes | rtmp://host:port/app/stream-key |
| 9 | WHIP/WebRTC | No | Yes | whip://; used for encoded browser output/monitoring. |
| 10 | File | Yes | Yes | 188-byte TS only. 192-byte M2TS/AVCHD is rejected. |
SRT redundancy status
An SRT redundancy object in StatusAll contains:
{
"enabled": true,
"mode": "active-active",
"role": "caller",
"expectedLinks": 2,
"connectedLinks": 2,
"activeLinks": 2,
"healthy": true,
"primary": "192.168.100.10:9000",
"secondary": "192.168.50.10:9000"
}
Active-backup status can also include stabilityMs. Non-redundant transports return at least {"enabled":false}.
Protocol URL options
The complete URL is carried inside the setup JSON. These options are part of that URL, not top-level REST query parameters.
SRT
srt://primary.example:9000?mode=caller&latency=200&password=secret
srt://primary.example:9000?mode=caller&redundancy=active-active&secondary=backup.example:9000&interface=192.168.100.236&secondary_interface=192.168.50.80
srt://primary.example:9000?mode=caller&redundancy=active-backup&secondary=backup.example:9000&stability=60
| Option | Values/meaning |
|---|---|
mode | caller or listener. The transport also recognizes the first letter; rendezvous exists for non-redundant use but is not offered by the current UI. |
latency | Milliseconds. Active-backup enforces at least 200 ms. |
password / passphrase | SRT passphrase. password takes precedence. |
user | SRT username/stream identity field used by the transport. |
interface | Primary local interface address. |
redundancy | active-active (aliases active_active, hitless, broadcast) or active-backup (aliases active_backup, backup). |
secondary | host:port. Caller redundancy requires a valid secondary. The alternate form is secondary_host plus optional secondary_port. |
secondary_interface | Optional local interface address for the secondary link. |
stability | Active-backup failover stability time in milliseconds, minimum 60. |
Redundant rendezvous mode is rejected. Listener redundancy relies on the peer establishing the compatible two-link SRT group.
File
file:///G:/streams/golden.ts?loop=1&chunk=7
file:///G:/captures/output.ts?append=1&chunk=7
| Option | Meaning |
|---|---|
loop=1 | Loop a file input. |
append=1 | Append to a file output. |
chunk=N | File read/write TS packet grouping; the setup UI constrains N to 1..64. |
WHIP/WebRTC output
whip://host/path?vbitrate=2500&abitrate=128&width=1280&height=720&fps=30
Optional output controls are signaling/media port, vbitrate and abitrate in kbps, output width/height, and fps.
TLS protocol names
rtmps, hlss, and whips are not currently advertised by the UI because their TLS/certificate paths are not ready. Do not use them as supported secure transports.Client implementation notes
- Poll
/heartbeatseparately from stream status. A live service can legitimately report every stream as Off or Illegal. - For the main/details UI, poll
StatusAll. It is the authoritative combined source, destination, basic-analysis, and redundancy snapshot. - For events, begin with
after=0, retainnext_sequence, and send that value as the nextaftercursor. - Use
TsAnalyzeStatusonly for the currently selected full analyzer. Basic analysis for every active input is already present inStatusAll. - The monitor and analyzer source selections are independent. Changing either does not change the router's selected source/destination path.
- Use
value=0to clear monitor/analyzer selection or a traditional destination route. - Inspect
lockedafter route writes andstatus_msgwhen a status is Illegal. - Integer counters that can grow large are serialized as decimal strings. Parse them with a 64-bit integer type or JavaScript
BigIntwhen exactness matters. - The REST callback returns compatibility fallbacks for unknown requests. Treat an unexpected schema as an unsupported command.