Skip to content

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:

text
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 ​

sh
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.

jsonc
// 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.

RequestArgumentsDoesState
get_statusCurrent settings: timeouts, log level, NACK queue and so on.works
list_sessionsIds of all sessions.works
list_handlessession_idIds of the handles of a session.works
handle_infosession_id, handle_id, plugin_onlyEverything about a handle: ICE, DTLS, SDPs, RTCP stats per m-line, the plugin's own state.works
set_log_levellevel 0 to 7Change the log level now.works
set_log_timestamps, set_log_colorstimestamps, colorsToggle log decoration.works
set_session_timeouttimeout (s)New session timeout.works
set_min_nack_queue, set_nack_optimizations, set_no_media_timer, set_slowlink_thresholdone value eachMedia tuning.works
set_locking_debug, set_refcount_debugdebugAccepted and ignored: the Rust port has no such debug mode.accepted
accept_new_sessionsacceptWhen false, create fails with 472.works
destroy_sessionsession_idEnd a session from outside.works
detach_handle, hangup_webrtcsession_id, handle_idDetach a handle, or close its PeerConnection.works
message_pluginplugin, request (an object)Send a plugin its admin request.works
loops_infoEvent loops and the handles on each.works
resolve_addressaddressResolve a name.works
test_stunaddress, portAsk a STUN server for the public address.answers (error 490 STUN request failed for an address with no STUN server)
custom_event, custom_loglineschema, data; level, lineInject an event for the event handlers, or a line in the log.works
start_pcap, stop_pcap, start_text2pcap, stop_text2pcapsession_id, handle_id, folder, filenameDump a handle's packets.accepted (the files themselves are not checked here)
list_tokens, add_token, allow_token, disallow_token, remove_tokentoken, pluginsStored-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_eventhandlerhandler, 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_transporttransport, request (an object)Ask a transport about itself.error 490 Not supported in this build
query_loggerlogger, request (an object)Ask an external logger about itself.error 490 Not supported in this build
info, pingSame 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.

GPL-3.0-or-later, like the Janus gateway it ports.