Admin API walkthrough
The Admin API is the monitor endpoint. It shows who is connected, lets you look inside a handle, and changes settings while the server runs. It speaks the same JSON as the Janus API, on its own port and path, and every request carries the admin secret.
Turn it on
It is off by default. In janus.transport.http.jcfg:
admin: {
admin_http = true
admin_port = 7088
admin_base_path = "/admin"
}For WebSockets set admin_ws = true and admin_ws_port = 7188 in janus.transport.websockets.jcfg; the sub-protocol is janus-admin-protocol. The secret is admin_secret in janus.jcfg (the C sample's default is janusoverlord). Set it to something else. Anyone who has it can read your sessions and change your settings.
Request shape
curl -s -X POST http://127.0.0.1:7088/admin \
-d '{"janus":"list_sessions","transaction":"a1","admin_secret":"janusoverlord"}'Session and handle ids go in the path over HTTP (/admin/<session>/<handle>) and in the message over WebSockets, as with the Janus API.
// Every Admin request carries admin_secret in the body. Without it, or with a wrong one, the answer is 403.
// → POST /admin
{
"janus": "get_status",
"transaction": "ad0"
}
// ← 200 OK
{
"janus": "error",
"transaction": "ad0",
"error": {
"code": 403,
"reason": "Unauthorized request (wrong or missing secret/token)"
}
}
// → POST /admin
{
"janus": "get_status",
"transaction": "ad1",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"transaction": "ad1",
"status": {
"token_auth": false,
"session_timeout": 60,
"reclaim_session_timeout": 0,
"candidates_timeout": 45,
"log_level": 4,
"log_timestamps": false,
"log_colors": true,
"log_rotate_sig": 0,
"locking_debug": false,
"refcount_debug": false,
"min_nack_queue": 200,
"nack-optimizations": false,
"no_media_timer": 1,
"slowlink_threshold": 0
}
}
// → POST /admin
{
"janus": "list_sessions",
"transaction": "ad2",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"transaction": "ad2",
"sessions": [
797470682656374
]
}
// → POST /admin/797470682656374
{
"janus": "list_handles",
"transaction": "ad3",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"session_id": 797470682656374,
"transaction": "ad3",
"handles": [
2466416946430164
]
}
// → POST /admin/<session>/<handle>
{
"janus": "handle_info",
"transaction": "ad4",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"session_id": 797470682656374,
"transaction": "ad4",
"handle_id": 2466416946430164,
"info": {
"session_id": 797470682656374,
"session_last_activity": 77720,
"session_timeout": 60,
"session_transport": "janus.transport.http",
"handle_id": 2466416946430164,
"opaque_id": "docs-demo",
"loop-running": true,
"created": 77720,
"current_time": 79720,
"plugin": "janus.plugin.echotest",
"plugin_specific": {
"audio_active": true,
"video_active": true,
"bitrate": 0,
"peer-bitrate": 0,
"slowlink_count": 0,
"hangingup": 0,
"destroyed": 0
},
"flags": {
"got-offer": false,
"got-answer": false,
"negotiated": false,
"processing-offer": false,
"starting": false,
"ice-restart": false,
"ready": false,
"stopped": false,
"alert": true,
"trickle": false,
"all-trickles": false,
"resend-trickles": false,
"trickle-synced": false,
"data-channels": false,
"has-audio": false,
"has-video": false,
"new-datachan-sdp": false,
"rfc4588-rtx": false,
"cleaning": false,
"e2ee": false
},
"sdps": {},
"queued-packets": 0
}
}
// Change a setting while the server runs.
// → POST /admin
{
"janus": "set_log_level",
"level": 5,
"transaction": "ad5",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"transaction": "ad5",
"level": 5
}
// → POST /admin
{
"janus": "set_log_level",
"level": 4,
"transaction": "ad6",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"transaction": "ad6",
"level": 4
}
// → POST /admin
{
"janus": "set_session_timeout",
"timeout": 90,
"transaction": "ad7",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"transaction": "ad7",
"timeout": 90
}
// → POST /admin
{
"janus": "set_session_timeout",
"timeout": 60,
"transaction": "ad8",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"transaction": "ad8",
"timeout": 60
}
// Ask a plugin something through the Admin API.
// → POST /admin
{
"janus": "message_plugin",
"plugin": "janus.plugin.videoroom",
"request": {
"request": "list"
},
"transaction": "ad9",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"transaction": "ad9",
"response": {
"videoroom": "success",
"list": [
{
"room": 1234,
"description": "Demo Room",
"pin_required": false,
"is_private": false,
"max_publishers": 6,
"bitrate": 512000,
"fir_freq": 10,
"require_pvtid": false,
"require_e2ee": false,
"dummy_publisher": false,
"notify_joining": false,
"audiocodec": "opus",
"videocodec": "vp8",
"opus_fec": true,
"record": false,
"lock_record": false,
"num_participants": 0,
"audiolevel_ext": true,
"audiolevel_event": false,
"videoorient_ext": true,
"playoutdelay_ext": true,
"transport_wide_cc_ext": true
}
]
}
}
// Ask a transport about itself. This is one of the requests the port does not support yet (error 490).
// → POST /admin
{
"janus": "query_transport",
"transport": "janus.transport.http",
"request": {
"request": "info"
},
"transaction": "ad10",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "error",
"transaction": "ad10",
"error": {
"code": 490,
"reason": "Not supported in this build: query_transport"
}
}
// Close a session from the outside.
// → POST /admin
{
"janus": "destroy_session",
"session_id": 797470682656374,
"transaction": "ad11",
"admin_secret": "janusoverlord"
}
// ← 200 OK
{
"janus": "success",
"session_id": 797470682656374,
"transaction": "ad11"
}Requests
Checked against the Rust binary on 2026-11-04 with an Admin request each. Works means the reply was success with the same shape the C server sends; the others say what came back.
| Request | Arguments | Does | State |
|---|---|---|---|
get_status | Current settings: timeouts, log level, NACK queue and so on. | works | |
list_sessions | Ids of all sessions. | works | |
list_handles | session_id | Ids of the handles of a session. | works |
handle_info | session_id, handle_id, plugin_only | Everything about a handle: ICE, DTLS, SDPs, RTCP stats per m-line, the plugin's own state. | works |
set_log_level | level 0 to 7 | Change the log level now. | works |
set_log_timestamps, set_log_colors | timestamps, colors | Toggle log decoration. | works |
set_session_timeout | timeout (s) | New session timeout. | works |
set_min_nack_queue, set_nack_optimizations, set_no_media_timer, set_slowlink_threshold | one value each | Media tuning. | works |
set_locking_debug, set_refcount_debug | debug | Accepted and ignored: the Rust port has no such debug mode. | accepted |
accept_new_sessions | accept | When false, create fails with 472. | works |
destroy_session | session_id | End a session from outside. | works |
detach_handle, hangup_webrtc | session_id, handle_id | Detach a handle, or close its PeerConnection. | works |
message_plugin | plugin, request (an object) | Send a plugin its admin request. | works |
loops_info | Event loops and the handles on each. | works | |
resolve_address | address | Resolve a name. | works |
test_stun | address, port | Ask a STUN server for the public address. | answers (error 490 STUN request failed for an address with no STUN server) |
custom_event, custom_logline | schema, data; level, line | Inject an event for the event handlers, or a line in the log. | works |
start_pcap, stop_pcap, start_text2pcap, stop_text2pcap | session_id, handle_id, folder, filename | Dump a handle's packets. | accepted (the files themselves are not checked here) |
list_tokens, add_token, allow_token, disallow_token, remove_token | token, plugins | Stored-token authentication. | answer 490 Stored-Token based authentication disabled unless token_auth is on in janus.jcfg; with it on, written from the C source and not exercised here |
query_eventhandler | handler, request (an object) | Ask an event handler about itself. | answers 460 Invalid event handler when none is loaded; with one loaded, not exercised here |
query_transport | transport, request (an object) | Ask a transport about itself. | error 490 Not supported in this build |
query_logger | logger, request (an object) | Ask an external logger about itself. | error 490 Not supported in this build |
info, ping | Same as in the Janus API. | works |
Two requests are missing
query_transport and query_logger are not implemented yet. The C server answers them. This is on the status page and fails in the Bench check admin.queries.
request in message_plugin and in the three query_* requests is an object ({"request":"list"}), not a string. A string gets error 467.
Changing settings safely
set_* changes live in memory only. A restart goes back to the file. get_status before and after is the quickest way to see a change took.
Try it in the Bench
The Admin API page lists sessions and handles with a button to open handle_info, sets the log level, and has a template for every request above. The checks admin.auth, admin.sessions.http, admin.sessions.ws, admin.settings and admin.queries run them headless.